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验证码工具类
二、修改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
(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/javaee
<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="
<!--注解支持-->
<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="
<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(
10
);
if
(exChars==
null
||exChars.indexOf(t+
""
)<0
){
//
排除特殊字符
code.append(t);
i++;
}
}
break
;
//
仅字母(即大写字母、小写字母混合)
case
TYPE_LETTER_ONLY:
while
(i<length){
int
t=r.nextInt(
123
);
if
((t>=
97
||(t>=
65
&&t<=
90
))&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
//
数字、大写字母、小写字母混合
case
TYPE_ALL_MIXED:
while
(i<length){
int
t=r.nextInt(
123
);
if
((t>=
97
||(t>=
65
&&t<=
90
)||(t>=
48
&&t<=
57
))
&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
//
数字、大写字母混合
case
TYPE_NUM_UPPER:
while
(i<length){
int
t=r.nextInt(
91
);
if
((t>=
65
||(t>=
48
&&t<=
57
))&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
//
数字、小写字母混合
case
TYPE_NUM_LOWER:
while
(i<length){
int
t=r.nextInt(
123
);
if
((t>=
97
||(t>=
48
&&t<=
57
))&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
//
仅大写字母
case
TYPE_UPPER_ONLY:
while
(i<length){
int
t=r.nextInt(
91
);
if
((t>=
65
)&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
//
仅小写字母
case
TYPE_LOWER_ONLY:
while
(i<length){
int
t=r.nextInt(
123
);
if
((t>=
97
)&&(exChars==
null
||exChars.indexOf((
char
)t)<0
)){
code.append((
char
)t);
i++;
}
}
break
;
}
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=(
int
)(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?(
int
)((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(
255
),r.nextInt(
255
),r.nextInt(
255
));
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>
相关文章推荐
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(一)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(一)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(一)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(一)整合配置
- 将 Shiro 作为应用的权限基础 五:SpringMVC+Apache Shiro+JPA(hibernate)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(一)整合配置
- 将 Shiro 作为应用的权限基础 五:SpringMVC+Apache Shiro+JPA(hibernate)整合配置
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码
- Apache shiro+springmvc+springdata+jpa+swagger(零配置文件使用)
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(四)基于Shiro验证用户权限,且给用户授权
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(三)给Shiro登录验证加上验证码
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(五)关于源码及下载地址
- SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证