springmvc集成shiro登錄失敗處理操作
一般的登錄流程會(huì)有:用戶名不存在,密碼錯(cuò)誤,驗(yàn)證碼錯(cuò)誤等..
在集成shiro后,應(yīng)用程序的外部訪問權(quán)限以及訪問控制交給了shiro來管理。
shiro提供了兩個(gè)主要功能:認(rèn)證(Authentication)和授權(quán)(Authorization);認(rèn)證的作用是證明自身可以訪問,一般是用戶名加密碼,授權(quán)的作用是誰可以訪問哪些資源,通過開發(fā)者自己的用戶角色權(quán)限系統(tǒng)來控制。
shiro的會(huì)話管理和緩存管理不在本文范圍內(nèi)。
下面通過登錄失敗的處理流程來介紹springmvc與shiro的集成。
依賴項(xiàng)目
依賴名稱 | 版本 |
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>
新建一個(gè)spring-context-shiro.xml配置shiro相關(guān)信息,使用spring加載
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="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/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" default-lazy-init="true"> <description>Shiro Configuration</description> <!-- 安全認(rèn)證過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/sys/login" /> <property name="successUrl" value="/sys" /> <property name="filters"> <map> <!--自定義登錄驗(yàn)證過濾器--> <entry key="authc" value-ref="formAuthenticationFilter" /> </map> </property> <property name="filterChainDefinitions"> <value> /sys/login = authc /sys/logout = logout /sys/** = user </value> </property> </bean> <!-- 定義 Shiro 主要業(yè)務(wù)對(duì)象 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="systemAuthorizingRealm" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 會(huì)話ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 會(huì)話管理器,設(shè)定會(huì)話超時(shí)及保存 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- 全局會(huì)話超時(shí)時(shí)間(單位毫秒),默認(rèn)30分鐘 --> <property name="globalSessionTimeout" value="1800000" /> <property name="sessionDAO" ref="sessionDAO"/> </bean> <!-- 會(huì)話驗(yàn)證調(diào)度器,每30分鐘執(zhí)行一次驗(yàn)證 --> <!-- <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <property name="interval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- sessionDAO保存認(rèn)證信息 --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache" /> <property name="cacheManager" ref="shiroCacheManager" /> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 用戶授權(quán)信息Cache, 采用EhCache --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- Shiro生命周期處理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- AOP式方法級(jí)權(quán)限檢查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> </beans>
新建一個(gè)登錄認(rèn)證過濾器FormAuthenticationFilter.java
import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.web.util.WebUtils; import org.springframework.stereotype.Service; /** * 表單驗(yàn)證(包含驗(yàn)證碼)過濾類*/ @Service public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter { public static final String DEFAULT_CAPTCHA_PARAM = "validateCode"; private String captchaParam = DEFAULT_CAPTCHA_PARAM; public String getCaptchaParam() { return captchaParam; } protected String getCaptcha(ServletRequest request) { return WebUtils.getCleanParam(request, getCaptchaParam()); } protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); String locale = request.getParameter("locale"); if (password == null) { password = ""; } boolean rememberMe = isRememberMe(request); String host = getHost(request); String captcha = getCaptcha(request); return new UsernamePasswordToken(username, password.toCharArray(),locale, rememberMe, host, captcha); } }
新建令牌類UsernamePasswordToken.java
package com.chunhui.webservice.modules.sys.security; /** * 用戶和密碼(包含驗(yàn)證碼)令牌類*/ public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken { private static final long serialVersionUID = 1L; private String captcha; private String locale; public String getCaptcha() { return captcha; } public void setCaptcha(String captcha) { this.captcha = captcha; } public String getLocale() { return locale; } public void setLocale(String locale) { this.locale = locale; } public UsernamePasswordToken() { super(); } public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) { super(username, password, rememberMe, host); this.captcha = captcha; } public UsernamePasswordToken(String username, char[] password, String locale,boolean rememberMe, String host, String captcha) { super(username, password, rememberMe, host); this.captcha = captcha; this.locale = locale; } }
最后一個(gè)是認(rèn)證實(shí)現(xiàn)類SystemAuthorizationRealm:
package com.chunhui.webservice.modules.sys.security; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import com.chunhui.webservice.common.utils.EmployeeType; import com.chunhui.webservice.common.utils.VertifyStatus; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cache.Cache; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; import com.chunhui.webservice.common.servlet.ValidateCodeServlet; import com.chunhui.webservice.common.utils.SpringContextHolder; import com.chunhui.webservice.modules.sys.entity.Employee; import com.chunhui.webservice.modules.sys.entity.Menu; import com.chunhui.webservice.modules.sys.service.SystemService; import com.chunhui.webservice.modules.sys.utils.SystemUtils; import com.chunhui.webservice.modules.sys.web.LoginController; /** * 系統(tǒng)安全認(rèn)證實(shí)現(xiàn)類*/ @Service @DependsOn({ "employeeDao", "roleDao", "menuDao" }) public class SystemAuthorizingRealm extends AuthorizingRealm { private SystemService systemService; /** * 認(rèn)證回調(diào)函數(shù), 登錄時(shí)調(diào)用 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; // 判斷驗(yàn)證碼 Session session = SecurityUtils.getSubject().getSession(); // 設(shè)置獨(dú)立的session會(huì)話超時(shí)時(shí)間 session.setTimeout(60000); String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE); if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) { throw new CaptchaException("驗(yàn)證碼錯(cuò)誤!"); } //如果帳號(hào)不存在,輸出 //throw new UnknownAccountException(); //如果帳號(hào)被禁用,輸出 //throw new DisabledAccountException(); //保存登錄時(shí)選擇的語言 SecurityUtils.getSubject().getSession().setAttribute("locale", token.getLocale()); try{ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(new Principal(employee), employee.getPassword(), getName()); return info; }catch (Throwable t){ t.printStackTrace(); throw new AuthenticationException(); } }/** * 授權(quán)查詢回調(diào)函數(shù), 進(jìn)行鑒權(quán)但緩存中無用戶的授權(quán)信息時(shí)調(diào)用 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Principal principal = (Principal) getAvailablePrincipal(principals); Employee employee = getSystemService().getEmployeeByName(principal.getUsername()); if (employee != null) { SystemUtils.putCache("employee", employee); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); List<Menu> list = SystemUtils.getMenuList(); for (Menu menu : list) { if (StringUtils.isNotBlank(menu.getPermission())) { // 添加基于Permission的權(quán)限信息 for (String permission : StringUtils.split(menu.getPermission(), ",")) { info.addStringPermission(permission); } } } // 更新登錄IP和時(shí)間 getSystemService().updateEmployeeLoginInfo(employee.getId()); return info; } else { return null; } } /** * 清空用戶關(guān)聯(lián)權(quán)限認(rèn)證,待下次使用時(shí)重新加載 */ public void clearCachedAuthorizationInfo(String principal) { SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName()); clearCachedAuthorizationInfo(principals); } /** * 清空所有關(guān)聯(lián)認(rèn)證 */ public void clearAllCachedAuthorizationInfo() { Cache<Object, AuthorizationInfo> cache = getAuthorizationCache(); if (cache != null) { for (Object key : cache.keys()) { cache.remove(key); } } } /** * 獲取系統(tǒng)業(yè)務(wù)對(duì)象 */ public SystemService getSystemService() { if (systemService == null) { systemService = SpringContextHolder.getBean(SystemService.class); } return systemService; } /** * 授權(quán)用戶信息 */ public static class Principal implements Serializable { private static final long serialVersionUID = 1L; private String id; private String username; private String realname; private Map<String, Object> cacheMap; public Principal(Employee employee) { this.id = employee.getId(); this.username = employee.getUsername(); this.realname = employee.getRealname(); } public String getId() { return id; } public String getUsername() { return username; } public String getRealname() { return realname; } public Map<String, Object> getCacheMap() { if (cacheMap == null) { cacheMap = new HashMap<String, Object>(); } return cacheMap; } } }
那么在JSP頁面,可以通過獲取登錄異常具體的異常類型來在頁面顯示錯(cuò)誤原因
<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%> <c:set var="exp_type" value="<%=error %>"/> <c:set var="tips" value=""></c:set> <c:if test="${fn:contains(exp_type,'CaptchaException')}"> <c:set var="tips" value="驗(yàn)證碼錯(cuò)誤"></c:set> </c:if> <c:if test="${fn:contains(exp_type,'FailVertifyException')}"> <c:set var="tips" value="該賬號(hào)審核未通過,不允許登陸!"></c:set> </c:if> <c:if test="${fn:contains(exp_type,'NotVertifyException')}"> <c:set var="tips" value="該賬號(hào)正在審核中... 不允許登陸!"></c:set> </c:if> <c:if test="${fn:contains(exp_type,'UnknownAccountException')}"> <c:set var="tips" value="賬號(hào)不存在!"></c:set> </c:if> <c:if test="${fn:contains(exp_type,'DisabledAccountException')}"> <c:set var="tips" value="賬號(hào)不允許登陸!"></c:set> </c:if> <c:if test="${fn:contains(exp_type,'IncorrectCredentialsException')}"> <c:set var="tips" value="密碼錯(cuò)誤!"></c:set> </c:if>
以上這篇springmvc集成shiro登錄失敗處理操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解springboot和vue前后端分離開發(fā)跨域登陸問題
這篇文章主要介紹了詳解springboot和vue前后端分離開發(fā)跨域登陸問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Java技巧函數(shù)方法實(shí)現(xiàn)二維數(shù)組遍歷
這篇文章主要介紹了Java技巧函數(shù)方法實(shí)現(xiàn)二維數(shù)組遍歷,二維數(shù)組遍歷,每個(gè)元素判斷下是否為偶數(shù),相關(guān)內(nèi)容需要的小伙伴可以參考一下2022-08-08如何解決SpringBoot2.x版本對(duì)Velocity模板不支持的方案
這篇文章主要介紹了如何解決SpringBoot2.x版本對(duì)Velocity模板不支持的方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12SpringBoot任務(wù)調(diào)度器的實(shí)現(xiàn)代碼
SpringBoot自帶了任務(wù)調(diào)度器,通過注解的方式使用。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12Maven項(xiàng)目web多圖片上傳及格式驗(yàn)證的實(shí)現(xiàn)
本文主要介紹了Maven項(xiàng)目web多圖片上傳及格式驗(yàn)證的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10簡(jiǎn)單了解springboot中的配置文件相關(guān)知識(shí)
這篇文章主要介紹了簡(jiǎn)單了解springboot中的配置文件相關(guān)知識(shí),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Maven?Web項(xiàng)目使用Cargo插件實(shí)現(xiàn)自動(dòng)化部署的詳細(xì)步驟
cargo ,它是一組幫助用戶實(shí)現(xiàn)自動(dòng)化部署,操作Web容器的工具,并且?guī)缀踔С炙械腤eb容器,這篇文章主要介紹了Maven?Web項(xiàng)目使用Cargo實(shí)現(xiàn)自動(dòng)化部署,需要的朋友可以參考下2023-02-02Java自定義異常_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java自定義異常_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-04-04