springmvc集成shiro登录权限示例代码
一般的登录流程会有:用户名不存在,密码错误,验证码错误等..
在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。
shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制。
shiro的会话管理和缓存管理不在本文范围内。
下面通过登录失败的处理流程来介绍springmvc与shiro的集成。
项目依赖:
依赖名称
版本
spring
4.1.4.RELEASE
shiro
1.2.2
self4j
1.7.5
log4j
1.2.17
在web.xml里配置shiro
<filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
新建一个spring-context-shiro.xml配置shiro相关信息,使用spring加载
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" 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.2.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsd" default-lazy-init="true"> <description>ShiroConfiguration</description> <!--安全认证过滤器--> <beanid="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <propertyname="securityManager"ref="securityManager"/> <propertyname="loginUrl"value="/sys/login"/> <propertyname="successUrl"value="/sys"/> <propertyname="filters"> <map> <!--自定义登录验证过滤器--> <entrykey="authc"value-ref="formAuthenticationFilter"/> </map> </property> <propertyname="filterChainDefinitions"> <value> /sys/login=authc /sys/logout=logout /sys/**=user </value> </property> </bean> <!--定义Shiro主要业务对象--> <beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <propertyname="realm"ref="systemAuthorizingRealm"/> <propertyname="cacheManager"ref="shiroCacheManager"/> </bean> <!--会话ID生成器--> <beanid="sessionIdGenerator"class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!--会话管理器,设定会话超时及保存--> <beanid="sessionManager"class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!--全局会话超时时间(单位毫秒),默认30分钟--> <propertyname="globalSessionTimeout"value="1800000"/> <propertyname="sessionDAO"ref="sessionDAO"/> </bean> <!--会话验证调度器,每30分钟执行一次验证--> <!--<beanid="sessionValidationScheduler"class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">--> <beanid="sessionValidationScheduler"class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <propertyname="interval"value="1800000"/> <propertyname="sessionManager"ref="sessionManager"/> </bean> <!--sessionDAO保存认证信息--> <beanid="sessionDAO"class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <propertyname="activeSessionsCacheName"value="shiro-activeSessionCache"/> <propertyname="cacheManager"ref="shiroCacheManager"/> <propertyname="sessionIdGenerator"ref="sessionIdGenerator"/> </bean> <!--用户授权信息Cache,采用EhCache--> <beanid="shiroCacheManager"class="org.apache.shiro.cache.ehcache.EhCacheManager"> <propertyname="cacheManager"ref="cacheManager"/> </bean> <!--Shiro生命周期处理器--> <beanid="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!--AOP式方法级权限检查--> <beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor"> <propertyname="proxyTargetClass"value="true"/> </bean> <beanclass="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <propertyname="securityManager"ref="securityManager"/> </bean> </beans>
新建一个登录认证过滤器FormAuthenticationFilter.java
importjavax.servlet.ServletRequest; importjavax.servlet.ServletResponse; importorg.apache.shiro.authc.AuthenticationToken; importorg.apache.shiro.web.util.WebUtils; importorg.springframework.stereotype.Service; /** *表单验证(包含验证码)过滤类*/ @Service publicclassFormAuthenticationFilterextendsorg.apache.shiro.web.filter.authc.FormAuthenticationFilter{ publicstaticfinalStringDEFAULT_CAPTCHA_PARAM="validateCode"; privateStringcaptchaParam=DEFAULT_CAPTCHA_PARAM; publicStringgetCaptchaParam(){ returncaptchaParam; } protectedStringgetCaptcha(ServletRequestrequest){ returnWebUtils.getCleanParam(request,getCaptchaParam()); } protectedAuthenticationTokencreateToken(ServletRequestrequest,ServletResponseresponse){ Stringusername=getUsername(request); Stringpassword=getPassword(request); Stringlocale=request.getParameter("locale"); if(password==null){ password=""; } booleanrememberMe=isRememberMe(request); Stringhost=getHost(request); Stringcaptcha=getCaptcha(request); returnnewUsernamePasswordToken(username,password.toCharArray(),locale,rememberMe,host,captcha); } }
新建令牌类UsernamePasswordToken.java
packagecom.chunhui.webservice.modules.sys.security; /** *用户和密码(包含验证码)令牌类*/ publicclassUsernamePasswordTokenextendsorg.apache.shiro.authc.UsernamePasswordToken{ privatestaticfinallongserialVersionUID=1L; privateStringcaptcha; privateStringlocale; publicStringgetCaptcha(){ returncaptcha; } publicvoidsetCaptcha(Stringcaptcha){ this.captcha=captcha; } publicStringgetLocale(){ returnlocale; } publicvoidsetLocale(Stringlocale){ this.locale=locale; } publicUsernamePasswordToken(){ super(); } publicUsernamePasswordToken(Stringusername,char[]password,booleanrememberMe,Stringhost,Stringcaptcha){ super(username,password,rememberMe,host); this.captcha=captcha; } publicUsernamePasswordToken(Stringusername,char[]password,Stringlocale,booleanrememberMe,Stringhost,Stringcaptcha){ super(username,password,rememberMe,host); this.captcha=captcha; this.locale=locale; } }
最后一个是认证实现类SystemAuthorizationRealm:
packagecom.chunhui.webservice.modules.sys.security; importjava.io.Serializable; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importjavax.annotation.PostConstruct; importcom.chunhui.webservice.common.utils.EmployeeType; importcom.chunhui.webservice.common.utils.VertifyStatus; importorg.apache.commons.lang3.StringUtils; importorg.apache.shiro.SecurityUtils; importorg.apache.shiro.authc.*; importorg.apache.shiro.authc.credential.HashedCredentialsMatcher; importorg.apache.shiro.authz.AuthorizationInfo; importorg.apache.shiro.authz.SimpleAuthorizationInfo; importorg.apache.shiro.cache.Cache; importorg.apache.shiro.realm.AuthorizingRealm; importorg.apache.shiro.session.Session; importorg.apache.shiro.subject.PrincipalCollection; importorg.apache.shiro.subject.SimplePrincipalCollection; importorg.apache.shiro.subject.Subject; importorg.springframework.context.annotation.DependsOn; importorg.springframework.stereotype.Service; importcom.chunhui.webservice.common.servlet.ValidateCodeServlet; importcom.chunhui.webservice.common.utils.SpringContextHolder; importcom.chunhui.webservice.modules.sys.entity.Employee; importcom.chunhui.webservice.modules.sys.entity.Menu; importcom.chunhui.webservice.modules.sys.service.SystemService; importcom.chunhui.webservice.modules.sys.utils.SystemUtils; importcom.chunhui.webservice.modules.sys.web.LoginController; /** *系统安全认证实现类*/ @Service @DependsOn({"employeeDao","roleDao","menuDao"}) publicclassSystemAuthorizingRealmextendsAuthorizingRealm{ privateSystemServicesystemService; /** *认证回调函数,登录时调用 */ @Override protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthcToken)throwsAuthenticationException{ UsernamePasswordTokentoken=(UsernamePasswordToken)authcToken; //判断验证码 Sessionsession=SecurityUtils.getSubject().getSession(); //设置独立的session会话超时时间session.setTimeout(60000); Stringcode=(String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); if(token.getCaptcha()==null||!token.getCaptcha().toUpperCase().equals(code)){ thrownewCaptchaException("验证码错误!"); } //如果帐号不存在,输出 //thrownewUnknownAccountException(); //如果帐号被禁用,输出 //thrownewDisabledAccountException(); //保存登录时选择的语言 SecurityUtils.getSubject().getSession().setAttribute("locale",token.getLocale()); try{ SimpleAuthenticationInfoinfo=newSimpleAuthenticationInfo(newPrincipal(employee),employee.getPassword(),getName()); returninfo; }catch(Throwablet){ t.printStackTrace(); thrownewAuthenticationException(); } }/** *授权查询回调函数,进行鉴权但缓存中无用户的授权信息时调用 */ @Override protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){ Principalprincipal=(Principal)getAvailablePrincipal(principals); Employeeemployee=getSystemService().getEmployeeByName(principal.getUsername()); if(employee!=null){ SystemUtils.putCache("employee",employee); SimpleAuthorizationInfoinfo=newSimpleAuthorizationInfo(); List<Menu>list=SystemUtils.getMenuList(); for(Menumenu:list){ if(StringUtils.isNotBlank(menu.getPermission())){ //添加基于Permission的权限信息 for(Stringpermission:StringUtils.split(menu.getPermission(),",")){ info.addStringPermission(permission); } } } //更新登录IP和时间 getSystemService().updateEmployeeLoginInfo(employee.getId()); returninfo; }else{ returnnull; } } /** *清空用户关联权限认证,待下次使用时重新加载 */ publicvoidclearCachedAuthorizationInfo(Stringprincipal){ SimplePrincipalCollectionprincipals=newSimplePrincipalCollection(principal,getName()); clearCachedAuthorizationInfo(principals); } /** *清空所有关联认证 */ publicvoidclearAllCachedAuthorizationInfo(){ Cache<Object,AuthorizationInfo>cache=getAuthorizationCache(); if(cache!=null){ for(Objectkey:cache.keys()){ cache.remove(key); } } } /** *获取系统业务对象 */ publicSystemServicegetSystemService(){ if(systemService==null){ systemService=SpringContextHolder.getBean(SystemService.class); } returnsystemService; } /** *授权用户信息 */ publicstaticclassPrincipalimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; privateStringid; privateStringusername; privateStringrealname; privateMap<String,Object>cacheMap; publicPrincipal(Employeeemployee){ this.id=employee.getId(); this.username=employee.getUsername(); this.realname=employee.getRealname(); } publicStringgetId(){ returnid; } publicStringgetUsername(){ returnusername; } publicStringgetRealname(){ returnrealname; } publicMap<String,Object>getCacheMap(){ if(cacheMap==null){ cacheMap=newHashMap<String,Object>(); } returncacheMap; } } }
那么在JSP页面,可以通过获取登录异常具体的异常类型来在页面显示错误原因
<%Stringerror=(String)request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%> <c:setvar="exp_type"value="<%=error%>"/> <c:setvar="tips"value=""></c:set> <c:iftest="${fn:contains(exp_type,'CaptchaException')}"> <c:setvar="tips"value="验证码错误"></c:set> </c:if> <c:iftest="${fn:contains(exp_type,'FailVertifyException')}"> <c:setvar="tips"value="该账号审核未通过,不允许登陆!"></c:set> </c:if> <c:iftest="${fn:contains(exp_type,'NotVertifyException')}"> <c:setvar="tips"value="该账号正在审核中...不允许登陆!"></c:set> </c:if> <c:iftest="${fn:contains(exp_type,'UnknownAccountException')}"> <c:setvar="tips"value="账号不存在!"></c:set> </c:if> <c:iftest="${fn:contains(exp_type,'DisabledAccountException')}"> <c:setvar="tips"value="账号不允许登陆!"></c:set> </c:if> <c:iftest="${fn:contains(exp_type,'IncorrectCredentialsException')}"> <c:setvar="tips"value="密码错误!"></c:set> </c:if>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。