您的位置:首页 > 运维架构 > Apache

SpringMVC+Apache Shiro+JPA 整合

2014-07-26 16:50 465 查看
一、SpringMVC+ApacheShiro+JPA(hibernate)整合配置

(1)新建Web工程,且导入所需Jar包。(以下截图为真实项目中删减后保留,如有不需要的JAR包,请自行删除)



(2)配置web.xml,applicationContext.xml,spring-mvc.xml,log4j.properties

web.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0">

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<!--配置spring管理OpenEntityManagerInViewFilter-->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--Shirofilter-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>---------------------------?作用1
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置Log4j-->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>spring_springmvc_jpa.root</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>

<!--配置编码过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>-------------------?作用2
<filter-class>
org.springframework.web.filter.HiddenHttpMethodFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>dispatcherServlet</servlet-name>
</filter-mapping>

<!--SpringMVC核心分发器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 覆盖default servlet的/, springmvcservlet将处理原来处理静态资源的映射 -->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<jsp-config>
<jsp-property-group>
<display-name>JSPConfiguration</display-name>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
<page-encoding>utf-8</page-encoding>
<scripting-invalid>false</scripting-invalid>
</jsp-property-group>
</jsp-config>

<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>

</web-app>
applicationContext.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:cache="http://www.springframework.org/schema/cache"

xmlns:jaxws="http://cxf.apache.org/jaxws"

xsi:schemaLocation="

'target='_blank'>http://www.springframework.org/schema/beans----------------------------1
'target='_blank'>http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
'target='_blank'>http://www.springframework.org/schema/tx-------------------------------2
'target='_blank'>http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop------------------------------3

'target='_blank'>http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context--------------------------4

'target='_blank'>http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache----------------------------5

'target='_blank'>http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
http://cxf.apache.org/jaxwshttp://cxf.apache.org/schemas/jaxws.xsd">

<!--注解支持-->

<context:annotation-config/>

<!--启动组件扫描,排除@Controller组件,该组件由SpringMVC配置文件扫描-->

<context:component-scanbase-package="org.shiro.demo">

<context:exclude-filtertype="annotation"

expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

<!--属性文件位置-->

<context:property-placeholderlocation="classpath:jdbc.properties"/>

<!--数据源-->

<beanid="dataSource"class="com.jolbox.bonecp.BoneCPDataSource"

destroy-method="close">

<!--数据库驱动-->

<propertyname="driverClass"value="${jdbc.driverClassName}"/>

<!--相应驱动的jdbcUrl-->

<propertyname="jdbcUrl"value="${jdbc.url}"/>

<!--数据库的用户名-->

<propertyname="username"value="${jdbc.username}"/>

<!--数据库的密码-->

<propertyname="password"value="${jdbc.password}"/>

<!--检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0-->

<propertyname="idleConnectionTestPeriod"

value="${BoneCP.idleConnectionTestPeriod}"/>

<!--连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0-->

<propertyname="idleMaxAge"value="${BoneCP.idleMaxAge}"/>

<!--每个分区最大的连接数-->

<propertyname="maxConnectionsPerPartition"

value="${BoneCP.maxConnectionsPerPartition}"/>

<!--每个分区最小的连接数-->

<propertyname="minConnectionsPerPartition"

value="${BoneCP.minConnectionsPerPartition}"/>

<!--分区数,默认值2,最小1,推荐3-4,视应用而定-->

<propertyname="partitionCount"

value="${BoneCP.partitionCount}"/>

<!--每次去拿数据库连接的时候一次性要拿几个,默认值:2-->

<propertyname="acquireIncrement"

value="${BoneCP.acquireIncrement}"/>

<!--缓存preparedstatements的大小,默认值:0-->

<propertyname="statementsCacheSize"

value="${BoneCP.statementsCacheSize}"/>

<!--每个分区释放链接助理进程的数量,默认值:3,除非你的一个数据库连接的时间内做了很多工作,不然过多的助理进程会影响你的性能-->

<propertyname="releaseHelperThreads"

value="${BoneCP.releaseHelperThreads}"/>

</bean>

<!--JPA实体管理器工厂-->

<beanid="entityManagerFactory"

class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<propertyname="dataSource"ref="dataSource"/>

<propertyname="persistenceProvider"ref="persistenceProvider"/>

<propertyname="jpaVendorAdapter"ref="jpaVendorAdapter"/>

<propertyname="jpaDialect"ref="jpaDialect"/>

<propertyname="packagesToScan"value="org.shiro.demo.entity"/>

<propertyname="jpaProperties">

<props>

<propkey="hibernate.dialect">

org.hibernate.dialect.MySQL5Dialect

</prop>

<propkey="hibernate.connection.driver_class">

com.mysql.jdbc.Driver

</prop>

<propkey="hibernate.max_fetch_depth">3</prop>

<propkey="hibernate.jdbc.fetch_size">18</prop>

<propkey="hibernate.jdbc.batch_size">10</prop>

<propkey="hibernate.hbm2ddl.auto">update</prop><!--validate/update/create-->

<propkey="hibernate.show_sql">true</prop>

<propkey="hibernate.format_sql">false</prop>

<propkey="javax.persistence.validation.mode">none</prop>

</props>

</property>

</bean>

<beanid="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<propertyname="defaultEncoding"value="utf-8"></property>

</bean>

<!--用于指定持久化实现厂商类-->

<beanid="persistenceProvider"

class="org.hibernate.ejb.HibernatePersistence"/>

<!--用于设置JPA实现厂商的特定属性-->

<beanid="jpaVendorAdapter"

class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

<propertyname="database"value="MYSQL"/>

</bean>

<!--用于指定一些高级特性-->

<beanid="jpaDialect"

class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

<!--事务管理器-->

<beanid="txManager"

class="org.springframework.orm.jpa.JpaTransactionManager">

<propertyname="entityManagerFactory"

ref="entityManagerFactory"/>

</bean>

<!--注解式事务-->

<tx:annotation-driventransaction-manager="txManager"/>

<beanid="securityManager"

class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<propertyname="realm"ref="shiroDbRealm"/>

</bean>

<!--項目自定义的Realm-->

<beanid="shiroDbRealm"class="org.shiro.demo.service.realm.ShiroDbRealm"></bean>

<!--ShiroFilter-->

<beanid="shiroFilter"

class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

<propertyname="securityManager"ref="securityManager"/>

<propertyname="loginUrl"value="/"/>

<propertyname="successUrl"value="/system/main"/>

<propertyname="unauthorizedUrl"value="/system/error"/>

<propertyname="filterChainDefinitions">

<value>

/login=anon

/validateCode=anon

/**=authc

</value>

</property>

</bean>

</beans>

spring-mvc.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<mvc:annotation-driven/>

<!--默认访问跳转到登录页面-->

<mvc:view-controllerpath="/"view-name="forward:/login"/>

<context:component-scanbase-package="org.shiro.demo.controller"/>

<mvc:resourcesmapping="/resources/**"location="/resources/"/>

<!--采用SpringMVC自带的JSON转换工具,支持@ResponseBody注解-->

<beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

<propertyname="messageConverters">

<list>

<beanclass="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

</list>

</property>

</bean>

<!--避免IE执行AJAX时,返回JSON出现下载文件-->

<beanid="mappingJacksonHttpMessageConverter"

class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">

<propertyname="supportedMediaTypes">

<list>

<value>text/html;charset=UTF-8</value>

</list>

</property>

</bean>

<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">

<propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>

<propertyname="prefix"value="/"/>

<propertyname="suffix"value=".jsp"/>

</bean>

<!--开启Shiro注解的Spring配置方式的beans。在lifecycleBeanPostProcessor之后运行-->

<bean

class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"

depends-on="lifecycleBeanPostProcessor"/>

<bean

class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

<propertyname="securityManager"ref="securityManager"/>

</bean>

<beanid="lifecycleBeanPostProcessor"

class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

<!--shiro为集成spring-->

<beanclass="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

<propertyname="exceptionMappings">

<props>

<propkey="org.apache.shiro.authz.UnauthorizedException">/system/error</prop>

</props>

</property>

</bean>

</beans>

jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=UTF-8

jdbc.username=root

jdbc.password=root

BoneCP.idleConnectionTestPeriod=60

BoneCP.idleMaxAge=60

BoneCP.maxConnectionsPerPartition=5

BoneCP.minConnectionsPerPartition=1

BoneCP.partitionCount=3

BoneCP.acquireIncrement=2

BoneCP.statementsCacheSize=0

BoneCP.releaseHelperThreads=3

log4j.properties

log4j.rootLogger=INFO,stdout,file

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-ddHH\:mm\:ss,SSS}[%c]-[%p]%m%n

log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=${spring_springmvc_jpa.root}/shirodemo.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-ddHH:mm:ss,SSS}[%t][%c][%p]-%m%n

log4j.logger.org.hibernate.tool.hbm2ddl=info
(3)建立JavaBean,User.java,Role.java,Permisson.java

packageorg.shiro.demo.entity;

importjava.io.Serializable;

importjava.util.Collection;

importjavax.persistence.CascadeType;

importjavax.persistence.Column;

importjavax.persistence.Entity;

importjavax.persistence.GeneratedValue;

importjavax.persistence.GenerationType;

importjavax.persistence.Id;

importjavax.persistence.JoinColumn;

importjavax.persistence.JoinTable;

importjavax.persistence.ManyToMany;

importjavax.persistence.Table;

importorg.codehaus.jackson.annotate.JsonIgnore;

@Entity

@Table(name="CMSUser")

publicclassUserimplementsSerializable{

privatestaticfinallongserialVersionUID=7419229779731522702L;

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="userid")

privateLongid;

@Column(length=50,unique=true)

privateStringaccount;

@Column(length=100)

@JsonIgnore//springmvc生成json不包含此字段

privateStringpassword;

@Column(length=50)

privateStringnickname;

@ManyToMany(cascade={CascadeType.PERSIST})------------------------------?作用3

@JsonIgnore

@JoinTable(name="CMSUserRole",joinColumns={@JoinColumn(name="userid",referencedColumnName="userid")},

inverseJoinColumns={@JoinColumn(name="roleid",referencedColumnName="roleid")})

privateCollection<Role>roles;

--------------------------------get、set方法-------------------------------------

publicLonggetId(){

returnid;

}

publicvoidsetId(Longid){

this.id=id;

}

publicStringgetAccount(){

returnaccount;

}

publicvoidsetAccount(Stringaccount){

this.account=account;

}

publicStringgetPassword(){

returnpassword;

}

publicvoidsetPassword(Stringpassword){

this.password=password;

}

publicStringgetNickname(){

returnnickname;

}

publicvoidsetNickname(Stringnickname){

this.nickname=nickname;

}

publicCollection<Role>getRoles(){

returnroles;

}

publicvoidsetRoles(Collection<Role>roles){

this.roles=roles;

}

/**

*本函数输出将作为默认的<shiro:principal/>输出.

*/

publicStringtoString(){

returnaccount;

}

}

packageorg.shiro.demo.entity;

importjava.io.Serializable;

importjava.util.Collection;

importjavax.persistence.Basic;

importjavax.persistence.CascadeType;

importjavax.persistence.Column;

importjavax.persistence.Entity;

importjavax.persistence.FetchType;

importjavax.persistence.GeneratedValue;

importjavax.persistence.GenerationType;

importjavax.persistence.Id;

importjavax.persistence.JoinColumn;

importjavax.persistence.JoinTable;

importjavax.persistence.ManyToMany;

importjavax.persistence.Table;

@Entity

@Table(name="CMSRole")

publicclassRoleimplementsSerializable{

privatestaticfinallongserialVersionUID=6177417450707400228L;

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="roleid")

privateLongid;

@Column(length=50)

privateStringname;

@Column(length=50)

privateStringdescription;

@ManyToMany(mappedBy="roles")

@Basic(fetch=FetchType.LAZY)

privateCollection<User>users;

@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.REFRESH,CascadeType.MERGE},fetch=FetchType.LAZY)

@JoinTable(name="CMSRolePms",

joinColumns={@JoinColumn(name="roleid",updatable=false)},---------------?作用4

inverseJoinColumns={@JoinColumn(name="pmsid",updatable=false)})

privateCollection<Permission>pmss;

--------------------------------get、set方法-------------------------------------

publicLonggetId(){

returnid;

}

publicvoidsetId(Longid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

publicStringgetDescription(){

returndescription;

}

publicvoidsetDescription(Stringdescription){

this.description=description;

}

publicCollection<User>getUsers(){

returnusers;

}

publicvoidsetUsers(Collection<User>users){

this.users=users;

}

publicCollection<Permission>getPmss(){

returnpmss;

}

publicvoidsetPmss(Collection<Permission>pmss){

this.pmss=pmss;

}

}

packageorg.shiro.demo.entity;

importjava.io.Serializable;

importjava.util.Collection;

importjavax.persistence.CascadeType;

importjavax.persistence.Column;

importjavax.persistence.Entity;

importjavax.persistence.FetchType;

importjavax.persistence.GeneratedValue;

importjavax.persistence.GenerationType;

importjavax.persistence.Id;

importjavax.persistence.JoinColumn;

importjavax.persistence.ManyToMany;

importjavax.persistence.ManyToOne;

importjavax.persistence.OneToMany;

importjavax.persistence.Table;

@Entity

@Table(name="CMSPermission")

publicclassPermissionimplementsSerializable{

privatestaticfinallongserialVersionUID=-8792590494605747957L;

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="pmsid")

privateLongid;

@Column(length=50)

privateStringname;

@Column(length=100)

privateStringdescription;

@Column(length=50)

privateStringpermission;

@ManyToOne(fetch=FetchType.LAZY)

@JoinColumn(name="parentid")

privatePermissionparent;

@OneToMany(mappedBy="parent",fetch=FetchType.LAZY,cascade={CascadeType.ALL})

privateCollection<Permission>children;

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="pmss")

privateCollection<Role>roles;

--------------------------------get、set方法-------------------------------------

publicLonggetId(){

returnid;

}

publicvoidsetId(Longid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

publicStringgetDescription(){

returndescription;

}

publicvoidsetDescription(Stringdescription){

this.description=description;

}

publicStringgetPermission(){

returnpermission;

}

publicvoidsetPermission(Stringpermission){

this.permission=permission;

}

publicPermissiongetParent(){

returnparent;

}

publicvoidsetParent(Permissionparent){

this.parent=parent;

}

publicCollection<Permission>getChildren(){

returnchildren;

}

publicvoidsetChildren(Collection<Permission>children){

this.children=children;

}

publicCollection<Role>getRoles(){

returnroles;

}

publicvoidsetRoles(Collection<Role>roles){

this.roles=roles;

}

}

二、SpringMVC+ApacheShiro+JPA(hibernate)案例教学(二)

一、Shiro配置的简要说明。
<!--項目自定义的Realm-->
<beanid="shiroDbRealm"class="org.shiro.demo.service.realm.ShiroDbRealm"></bean>

<!--ShiroFilter-->
<beanid="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<propertyname="securityManager"ref="securityManager"/>
<propertyname="loginUrl"value="/"/>
<propertyname="successUrl"value="/system/main"/>
<propertyname="unauthorizedUrl"value="/system/error"/>
<propertyname="filterChainDefinitions">
<value>
/login=anon
/validateCode=anon
/**=authc
</value>
</property>
</bean>
大致解释:

<beanid="shiroDbRealm"class="org.shiro.demo.service.realm.ShiroDbRealm"></bean>

这个就是指定Shiro验证用户登录的类为自定义的ShiroDbRealm.java。
在ShiroFilter当中:

securityManager:这个属性是必须的。

loginUrl:没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面
successUrl:登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。

unauthorizedUrl:没有权限默认跳转的页面。

filterChainDefinitions:就是需要验证的地址的列表,常用的包含anon、authc、perms、roles、user、logout。

/login=anon  代表后缀为/login的链接不验证

/**=authc   代表其它后缀的链接都进行登录验证,需登录后才能访问。
二、新建ShiroDbRealm类
packageorg.shiro.demo.service.realm;
importjavax.annotation.Resource;
importorg.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.AuthenticationInfo;
importorg.apache.shiro.authc.AuthenticationToken;
importorg.apache.shiro.authc.SimpleAuthenticationInfo;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.authz.AuthorizationInfo;
importorg.apache.shiro.realm.AuthorizingRealm;
importorg.apache.shiro.subject.PrincipalCollection;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.service.IUserService;

publicclassShiroDbRealmextendsAuthorizingRealm{

@Resource(name="userService")
privateIUserServiceuserService;

protectedAuthorizationInfodoGetAuthorizationInfo(
PrincipalCollectionprincipals){
returnnull;
}

/**
*认证回调函数,登录时调用.
*/
protectedAuthenticationInfodoGetAuthenticationInfo(
AuthenticationTokenauthcToken)throwsAuthenticationException{
UsernamePasswordTokentoken=(UsernamePasswordToken)authcToken;
Useruser=userService.getByAccount(token.getUsername());
if(user!=null){
returnnewSimpleAuthenticationInfo(user.getAccount(),user
.getPassword(),user.getNickname());
}else{
returnnull;
}
}
}
继承AuthorizingRealm类,且重写doGetAuthorizationInfo及doGetAuthenticationInfo方法。

doGetAuthorizationInfo:验证当前Subject(可理解为当前用户)所拥有的权限,且给其授权。在下一章说明。

doGetAuthenticationInfo:验证当前Subject登录。

userService.getByAccount(token.getUsername());是自定义的方法。
三、新建UserController.java类
@Controller
publicclassUserController{
privatestaticfinalLoglog=LogFactory.getLog(UserController.class);
/**
*判断用户是否登录
*@paramcurrUser
*@return
*/
@RequestMapping(value="/login",method=RequestMethod.POST)
publicStringisLogin(UsercurrUser){
Subjectuser=SecurityUtils.getSubject();
UsernamePasswordTokentoken=newUsernamePasswordToken(currUser.getAccount(),currUser.getPassword());
token.setRememberMe(true);
try{
user.login(token);
return"redirect:/main";
}catch(AuthenticationExceptione){
log.error("登录失败错误信息:"+e);
token.clear();
return"redirect:/login";
}
}
}
四、新建login.jsp
<formaction="<%=basePath%>/login"method="post">
用户名:<inputtype="text"name="account"/><br/>
密码:<inputtype="text"name="password"/><br/>
<inputtype="submit"value="登录"/>
</form>
然后通过SpringMVC访问到login.jsp页面,测试Shiro的用户验证。
五、SpringMVC+ApacheShiro+JPA(HIBERNATE)
案例教学(三)


一、新建ValidateCode.java验证码工具类
package
org.shiro.demo.util;


import
java.util.Random;


import
java.awt.image.BufferedImage;


import
java.awt.Graphics;


import
java.awt.Font;


import
java.awt.Color;


/**


*
验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。支持自定义验证码字符数量;支持自定义验证码图片的大小;支持自定义需排除的特殊字符;


*
支持自定义干扰线的数量;支持自定义验证码图文颜色


*/


public
class
ValidateCode{


/**


*
验证码类型为仅数字0~9


*/


public
static
final
int
TYPE_NUM_ONLY=0;


/**


*
验证码类型为仅字母,即大写、小写字母混合


*/


public
static
final
int
TYPE_LETTER_ONLY=1;


/**


*
验证码类型为数字、大写字母、小写字母混合


*/


public
static
final
int
TYPE_ALL_MIXED=2;


/**


*
验证码类型为数字、大写字母混合


*/


public
static
final
int
TYPE_NUM_UPPER=3;


/**


*
验证码类型为数字、小写字母混合


*/


public
static
final
int
TYPE_NUM_LOWER=4;


/**


*
验证码类型为仅大写字母


*/


public
static
final
int
TYPE_UPPER_ONLY=5;


/**


*
验证码类型为仅小写字母


*/


public
static
final
int
TYPE_LOWER_ONLY=
6
;


private
ValidateCode(){




}


/**


*
生成验证码字符串


*


*@paramtype


*
验证码类型,参见本类的静态属性


*@paramlength


*
验证码长度,大于0的整数


*@paramexChars


*
需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)


*@return
验证码字符串


*/


public
static
StringgenerateTextCode
(
int
type,
int
length,StringexChars){


if
(length<=
0
)


return
"
"
;


StringBuffercode=
new
StringBuffer();


int
i=
0
;


Randomr=
new
Random();


switch
(type){


//
仅数字


case
TYPE_NUM_ONLY:


while
(i<length){


int
t=r.nextInt
(
1
0
);


if
(exChars==
null
||exChars.indexOf(t+
"
"
)<
0
)
{
//
排除特殊字符


code.append(t);


i++;


}


}


brea
k
;


//
仅字母(即大写字母、小写字母混合)


case
TYPE_LETTER_ONLY:


while
(i<length){


int
t=r.nextInt
(
12
3
);


if
((t>=
97
||(t>=
65
&&t<=
9
0
))&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


//
数字、大写字母、小写字母混合


case
TYPE_ALL_MIXED:


while
(i<length){


int
t=r.nextInt
(
12
3
);


if
((t>=
97
||(t>=
65
&&t<=
9
0
)||(t>=
48
&&t<=
5
7
))


&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


//
数字、大写字母混合


case
TYPE_NUM_UPPER:


while
(i<length){


int
t=r.nextInt
(
9
1
);


if
((t>=
65
||(t>=
48
&&t<=
5
7
))&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


//
数字、小写字母混合


case
TYPE_NUM_LOWER:


while
(i<length){


int
t=r.nextInt
(
12
3
);


if
((t>=
97
||(t>=
48
&&t<=
5
7
))&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


//
仅大写字母


case
TYPE_UPPER_ONLY:


while
(i<length){


int
t=r.nextInt
(
9
1
);


if
((t>=
6
5
)&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


//
仅小写字母


case
TYPE_LOWER_ONLY:


while
(i<length){


int
t=r.nextInt
(
12
3
);


if
((t>=
9
7
)&&(exChars==
null
||exChars.indexOf(
(
cha
r
)t)<
0
)){


code.append(
(
cha
r
)t);


i++;


}


}


brea
k
;


}


return
code.toString();


}


/**


*
已有验证码,生成验证码图片


*


*@paramtextCode


*
文本验证码


*@paramwidth


*
图片宽度


*@paramheight


*
图片高度


*@paraminterLine


*
图片中干扰线的条数


*@paramrandomLocation


*
每个字符的高低位置是否随机


*@parambackColor


*
图片颜色,若为null,则采用随机颜色


*@paramforeColor


*
字体颜色,若为null,则采用随机颜色


*@paramlineColor


*
干扰线颜色,若为null,则采用随机颜色


*@return
图片缓存对象


*/


public
static
BufferedImagegenerateImageCode(StringtextCode,
int
width,
int
height,
int
interLine,


boolean
randomLocation,ColorbackColor,ColorforeColor,ColorlineColor){


BufferedImagebim=
new
BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);


Graphicsg=bim.getGraphics();


//
画背景图


g.setColor(backColor==
null
?getRandomColor():backColor);


g.fillRect
(0
,
0
,width,height);


//
画干扰线


Randomr=
new
Random();


if
(interLine>
0
){


int
x=
0
,y=
0
,x1=width,y1=
0
;


for
(
int
i=
0
;i<interLine;i++){


g.setColor(lineColor==
null
?getRandomColor():lineColor);


y=r.nextInt(height);


y1=r.nextInt(height);


g.drawLine(x,y,x1,y1);


}


}


//
写验证码


//g.setColor(getRandomColor());


//g.setColor(isSimpleColor?Color.BLACK:Color.WHITE);


//
字体大小为图片高度的80%


int
fsize=
(
in
t
)(height*
0.
8
);


int
fx=height-fsize;


int
fy=fsize;


g.setFont
(
new
Font
(
"Default
"
,Font.PLAIN,fsize));


//
写验证码字符


for
(
int
i=
0
;i<textCode.length();i++){


fy=randomLocation?
(
in
t
)((Math.random()*
0.3
+
0.
6
)*height):fy
;
//
每个字符高低是否随机


g.setColor(foreColor==
null
?getRandomColor():foreColor);


g.drawString(textCode.charAt(i)+
"
"
,fx,fy);


fx+=fsize*
0.
9
;


}


g.dispose();


return
bim;


}


/**


*
生成图片验证码


*


*@paramtype


*
验证码类型,参见本类的静态属性


*@paramlength


*
验证码字符长度,大于0的整数


*@paramexChars


*
需排除的特殊字符


*@paramwidth


*
图片宽度


*@paramheight


*
图片高度


*@paraminterLine


*
图片中干扰线的条数


*@paramrandomLocation


*
每个字符的高低位置是否随机


*@parambackColor


*
图片颜色,若为null,则采用随机颜色


*@paramforeColor


*
字体颜色,若为null,则采用随机颜色


*@paramlineColor


*
干扰线颜色,若为null,则采用随机颜色


*@return
图片缓存对象


*/


public
static
BufferedImagegenerateImageCode
(
int
type,
int
length,StringexChars,
int
width,
int
height,


int
interLine,
boolean
randomLocation,ColorbackColor,ColorforeColor,ColorlineColor){


StringtextCode=generateTextCode(type,length,exChars);


BufferedImagebim=generateImageCode(textCode,width,height,interLine,randomLocation,backColor,foreColor,


lineColor);


return
bim;


}


/**


*
产生随机颜色


*


*@return


*/


private
static
ColorgetRandomColor(){


Randomr=
new
Random();


Colorc=
new
Color(r.nextInt
(
25
5
),r.nextInt
(
25
5
),r.nextInt
(
25
5
));


return
c;


}


}

二、修改UserController.java的实现
packageorg.shiro.demo.controller;

importjava.awt.Color;
importjava.awt.image.BufferedImage;
importjava.io.IOException;

importjavax.imageio.ImageIO;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpSession;

importorg.apache.commons.lang.StringUtils;
importorg.apache.shiro.SecurityUtils;
importorg.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.subject.Subject;
importorg.apache.shiro.web.util.WebUtils;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.util.ValidateCode;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;

@Controller
publicclassLoginController{

@RequestMapping(value="/login",method=RequestMethod.POST,produces={"application/json;charset=UTF-8"})
publicStringlogin(UsercurrUser,HttpSessionsession,HttpServletRequestrequest){
Stringcode=(String)session.getAttribute("validateCode");
StringsubmitCode=WebUtils.getCleanParam(request,"validateCode");
if(StringUtils.isEmpty(submitCode)||!StringUtils.equals(code,submitCode.toLowerCase())){
return"redirect:/";
}
Subjectuser=SecurityUtils.getSubject();
UsernamePasswordTokentoken=newUsernamePasswordToken(currUser.getAccount(),currUser.getPassword());
token.setRememberMe(true);
try{
user.login(token);
return"/system/main";
}catch(AuthenticationExceptione){
token.clear();
return"redirect:/";
}
}

/**
*生成验证码
*@paramrequest
*@paramresponse
*@throwsIOException
*/
@RequestMapping(value="/validateCode")
publicvoidvalidateCode(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{
response.setHeader("Cache-Control","no-cache");
StringverifyCode=ValidateCode.generateTextCode(ValidateCode.TYPE_NUM_ONLY,4,null);
request.getSession().setAttribute("validateCode",verifyCode);
response.setContentType("image/jpeg");
BufferedImagebim=ValidateCode.generateImageCode(verifyCode,90,30,3,true,Color.WHITE,Color.BLACK,null);
ImageIO.write(bim,"JPEG",response.getOutputStream());
}
}
三、修改login.jsp
<%@pagelanguage="java"pageEncoding="utf-8"%>
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%
Stringpath=request.getContextPath();
StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%>
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">
<html>
<head>
<basehref="<%=basePath%>">
<title>shirodemologinpage</title>
<metahttp-equiv="content-type"content="text/html;charset=UTF-8">
<scripttype="text/javascript"src='<c:urlvalue="/resources/js/jquery-1.6.3.min.js"/>'></script>
<scripttype="text/javascript">
<!--
functionreloadValidateCode(){
$("#validateCodeImg").attr("src","<%=basePath%>/validateCode?data="+newDate()+Math.floor(Math.random()*24));
}
//-->
</script>
</head>

<body>
<formaction="<%=basePath%>/login"method="post">
<ul>
<li>姓 名:<inputtype="text"name="account"/></li>
<li>密 码:<inputtype="text"name="password"/></li>
<li>验证码:<inputtype="text"name="validateCode"/>  <imgid="validateCodeImg"src="<%=basePath%>/validateCode"/>  <ahref="#"onclick="javascript:reloadValidateCode();">看不清?</a></li>
<li><inputtype="submit"value="确认"/></li>
</ul>
</form>
</body>
</html>
至此,就给你的登陆页面加上验证码了。访问你的login.jsp试试?

六、SpringMVC+shiro+JPA(hibernate)案例教学(四)

一、修改ShiroDbRealm类,实现它的doGetAuthorizationInfo方法
packageorg.shiro.demo.service.realm;

importjava.util.ArrayList;
importjava.util.List;

importjavax.annotation.Resource;

importorg.apache.commons.lang.StringUtils;
importorg.apache.shiro.authc.AuthenticationException;
importorg.apache.shiro.authc.AuthenticationInfo;
importorg.apache.shiro.authc.AuthenticationToken;
importorg.apache.shiro.authc.SimpleAuthenticationInfo;
importorg.apache.shiro.authc.UsernamePasswordToken;
importorg.apache.shiro.authz.AuthorizationException;
importorg.apache.shiro.authz.AuthorizationInfo;
importorg.apache.shiro.authz.SimpleAuthorizationInfo;
importorg.apache.shiro.realm.AuthorizingRealm;
importorg.apache.shiro.subject.PrincipalCollection;
importorg.shiro.demo.entity.Permission;
importorg.shiro.demo.entity.Role;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.service.IUserService;

publicclassShiroDbRealmextendsAuthorizingRealm{

@Resource(name="userService")
privateIUserServiceuserService;

protectedAuthorizationInfodoGetAuthorizationInfo(
PrincipalCollectionprincipals){

SimpleAuthorizationInfoinfo=newSimpleAuthorizationInfo();
//获取当前登录的用户名
Stringaccount=(String)super.getAvailablePrincipal(principals);

List<String>roles=newArrayList<String>();
List<String>permissions=newArrayList<String>();
Useruser=userService.getByAccount(account);
if(user!=null){
if(user.getRoles()!=null&&user.getRoles().size()>0){
for(Rolerole:user.getRoles()){
roles.add(role.getName());
if(role.getPmss()!=null&&role.getPmss().size()>0){
for(Permissionpmss:role.getPmss()){
if(!StringUtils.isEmpty(pmss.getPermission())){
permissions.add(pmss.getPermission());
}
}
}
}
}
}else{
thrownewAuthorizationException();
}
//给当前用户设置角色
info.addRoles(roles);
//给当前用户设置权限
info.addStringPermissions(permissions);
returninfo;

}

/**
*认证回调函数,登录时调用.
*/
protectedAuthenticationInfodoGetAuthenticationInfo(
AuthenticationTokenauthcToken)throwsAuthenticationException{
UsernamePasswordTokentoken=(UsernamePasswordToken)authcToken;
Useruser=userService.getByAccount(token.getUsername());
if(user!=null){
returnnewSimpleAuthenticationInfo(user.getAccount(),user
.getPassword(),user.getNickname());
}else{
returnnull;
}
}
}
其实代码逻辑很简单,不过就是从principals获取当前用户名,然后读取user的role及permission信息。理解下就知道了。
二、初始化系统用户信息,利用ShiroAnnotation实现权限认证。
(一)新建testInitSystemDatajunit测试类。(本着快速测试的目的,我们利用springjunit测试来初始化数据!o(╯□╰)o)
packageorg.shiro.demo.junit;

importjava.util.ArrayList;
importjava.util.List;

importjavax.annotation.Resource;

importorg.junit.Test;
importorg.junit.runner.RunWith;
importorg.shiro.demo.entity.Permission;
importorg.shiro.demo.entity.Role;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.service.IBaseService;
importorg.springframework.test.context.ContextConfiguration;
importorg.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;
importorg.springframework.test.context.transaction.TransactionConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml","classpath:spring-mvc.xml"})
@TransactionConfiguration(transactionManager="txManager",defaultRollback=false)
publicclasstestInitSystemDataextendsAbstractTransactionalJUnit4SpringContextTests{

@Resource(name="baseService")
privateIBaseServicebaseService;

@Test
publicvoidinitPermission()throwsException{
List<Permission>list=newArrayList<Permission>();

Permissionpmss1=newPermission();
pmss1.setName("新建用户");
pmss1.setDescription("新建用户");
pmss1.setPermission("user:create");

Permissionpmss2=newPermission();
pmss2.setName("编辑用户");
pmss2.setDescription("编辑用户");
pmss2.setPermission("user:edit");

Permissionpmss3=newPermission();
pmss3.setName("删除用户");
pmss3.setDescription("删除用户");
pmss3.setPermission("user:delete");

Permissionpmss4=newPermission();
pmss4.setName("审核用户");
pmss4.setDescription("审核用户");
pmss4.setPermission("user:audit");

list.add(pmss1);
list.add(pmss2);
list.add(pmss3);
list.add(pmss4);

for(Permissionpms:list){
baseService.save(pms);
}
}

@Test
publicvoidinitAdminRole()throwsException{
List<Permission>list=newArrayList<Permission>();
list=(List<Permission>)baseService.getAll(Permission.class);

Rolerole=newRole();
role.setName("administrator");
role.setDescription("系统管理员角色");
role.setPmss(list);
baseService.save(role);
}

@Test
publicvoidinitAdminUser(){
List<Role>list=newArrayList<Role>();
Stringjpql="fromRoleasowhereo.name=?";
list=baseService.getByJpql(jpql,"administrator");
Useruser=newUser();
user.setAccount("admin");
user.setPassword("123456");
user.setNickname("july");
user.setRoles(list);
baseService.save(user);
}
}

(二)新建UserController类,新建用户注册页,并给用户注册上加上shiro权限验证,要求用户必须具备administrator角色
UserController.java
packageorg.shiro.demo.controller;

importjavax.annotation.Resource;

importorg.apache.shiro.authz.annotation.RequiresRoles;
importorg.shiro.demo.entity.User;
importorg.shiro.demo.service.IUserService;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value="/user")
publicclassUserController{
@Resource(name="userService")
privateIUserServiceuserService;
@RequestMapping(value="/register",method=RequestMethod.POST)
@ResponseBody
@RequiresRoles("administrator")
publicbooleanregister(Useruser){
returnuserService.register(user);
}
}
@RequiresRoles("administrator")就是我们使用的Shirro注解了。
register.jsp

<%@pagelanguage="java"pageEncoding="utf-8"%>
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%
Stringpath=request.getContextPath();
StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%>
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">
<html>
<head>
<basehref="<%=basePath%>">
<title>shirodemoregisterpage</title>
<metahttp-equiv="content-type"content="text/html;charset=UTF-8">
</head>

<body>
<formaction="<%=basePath%>/user/register"method="post">
<ul>
<li>姓 名:<inputtype="text"name="account"/></li>
<li>密 码:<inputtype="text"name="password"/></li>
<li>昵 称:<inputtype="text"name="nickname"/></li>
<li><inputtype="submit"value="确认"/></li>
</ul>
</form>
</body>
</html>

http://my.oschina.net/heroShane/blog?disp=3&catalog=444077&sort=time&p=3

/article/8884186.html

/article/8346489.html

http://www.sunnybtoc.com/page/M0/S852/852887.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐