- web.xml配置
<!-- 攔截到所有請求,由spring交給shiro處理 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <!-- 是否filter中的 init 和 destroy--> <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-shiro.xml配置
配置緩存管理器、憑證比對器(雜湊演算法,加鹽,散列次數)、會話管理器、自定義Realm(可以注入憑證比對器)、安全管理器(将自定義Realm注入)、自定義過濾器Filter、Shiro的Web過濾器(注入安全管理器,filterChainDefinitions,loginUrl等)
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--shiro核心過濾器--> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 如果配置了 loginUrl 沒有認證 執行對應的login請求 --> <property name="loginUrl" value="/static/login.html"/> <!--配置安全管理器--> <property name="securityManager" ref="securityManager"></property> <!-- 配置shiro過濾器pattern --> <property name="filterChainDefinitions"> <value> /static/css/** = anon <!--靜态檔案不需要登入驗證--> /static/images/** = anon /static/easyui/** = anon /static/json/** = anon /static/js/** = anon /static/login.html = anon /login = anon <!--登入請求不攔截--> /** = authc <!--除指定請求外,其它所有的請求都需要身份驗證--> </value> </property> </bean> <!-- 配置shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!--注入realm--> <property name="realm" ref="employeeRealm"/> </bean> <!--自定義Realm--> <bean class="fei.web.shiro.realm.EmployeeRealm" id="employeeRealm"> <!--注入憑證管理器--> <property name="credentialsMatcher" ref="credentialsMatcher"/> </bean> <!--憑證管理器--> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!--加密算法--> <property name="hashAlgorithmName" value="MD5"/> <!--加密次數--> <property name="hashIterations" value="3"/> </bean> </beans>
- LoginController中執行
SecurityUtils.getSubject().login(token);
token是UsernamePasswordToken類或者其子類
token會被一直傳,直到最後的自定義realm中,執行
方法,查詢資料庫,如果存在傳回SimpleAuthenticationInfo,自動進行密碼比對,判斷登陸成不成功doGetAuthenticationInfo()
/** * @function: 認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { LOG.info("來到了認證"); //擷取身份資訊 String username = (String) token.getPrincipal(); LOG.info("使用者名:" + username); //根據使用者名查詢有沒有目前使用者 Employee employee = employeeService.getEmployeeByUserName(username); //沒有查詢到或者不是管理者,直接傳回null if (employee == null) { return null; } if (employee.getAdmin() == false){ throw new NotAdminException("你不是管理者,不能通路"); } //定義加密的鹽值,是ByteSource類型 ByteSource salt = ByteSource.Util.bytes(employee.getUsername()); LOG.info("密碼明文:" + employee.getPassword()); /** * @function: 資料庫密碼加密(因為存的還是明文) * 參數:加密算法,密碼(需要加密的字段),加密的鹽值(通常為了區分各使用者,使用使用者主鍵),加密疊代次數 */ SimpleHash newpassword = new SimpleHash("MD5", employee.getPassword(), salt, 3); LOG.info("密碼密文:" + newpassword); /** * 因為目前realm配置了憑證管理器,是以token中的密碼會自動加密 * 就是将SimpleAuthenticationInfo的密碼與token的密碼進行比對判斷是否可以登入成功 * 參數: 主體,正确的密碼,鹽,目前realm名稱 * */ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(employee, newpassword, salt, this.getName()); return info; }
- LoginController中捕獲相關異常,傳回json回報資訊給前端
@RequestMapping("/login") public ResultMessage userLogin(Employee employee){ ResultMessage message = new ResultMessage(); try { TokenManager.login(employee); LOG.info("登入成功"); return ResultMessage.succ(); }catch (UnknownAccountException e){ message.setResultCode(200); message.setResultMes("賬戶不存在"); LOG.warn("賬戶不存在"); return message; }catch (NotAdminException e){ /這個是我的自定義異常 message.setResultCode(200); message.setResultMes(e.getMessage()); LOG.warn(e.getMessage()); return message; } catch (IncorrectCredentialsException e){ message.setResultCode(200); message.setResultMes("密碼錯誤"); LOG.warn("密碼錯誤"); return message; }catch (Exception e){ message.setResultCode(500); message.setResultMes("伺服器發生異常"); LOG.error(e.getMessage()); return message; } }
這就是我使用shiro進行登陸認證的流程及代碼,如果有問題謝謝指正,要不點個贊吧,哈哈