基於Shiro的用戶認證(不包含授權)
Spring整合Shiro
shiro原理
1.1 搭建環境
1.1.1 web模塊 pom.xml
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <!--shiro核心包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency>
1.1.2 Web.xml配置
<!-- Shiro Security filter filter-name這個名字的值將來還會在spring中用到,本段代碼原樣粘貼,注意該過濾器是代理過濾器,它什么都不干,可以通過再Spring整合中配置相應的過濾器權限攔截器進行相應的過濾器攔截--> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param>
<!--如果設置"targetFilterLifecycle"為true,則spring來管理Filter.init()和Filter.destroy();若為false,則這兩個方法失效--> <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>
1.1.3 Spring整合shiro applicationContext-shiro.xml
<description>Shiro與Spring整合</description> <!--安全管理器--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 引用自定義的realm --> <property name="realm" ref="authRealm"/> </bean> <!-- 自定義Realm域的編寫 --> <bean id="authRealm" class="此處為自定義Realm域的全限定類名"> <!-- 注入自定義Realm域的密碼比較器 --> <property name="credentialsMatcher" ref="customerCredentialsMatcher" ></property> </bean> <!-- 密碼比較器:密碼加密和比較 --> <bean id="customerCredentialsMatcher" class="自定義的證書匹配器所在的全限定類名"/> <!-- filter-name這個名字的值來自於web.xml中filter的名字 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!--登錄頁面 --> <property name="loginUrl" value="/login.jsp"></property> <!-- 登錄失敗后 跳轉到未經授權的頁面 --> <property name="unauthorizedUrl" value="/unauthorized.jsp"></property> <!--過濾器鏈定義,此處為訪問路徑設置過濾器鏈--> <property name="filterChainDefinitions"> <!-- /**代表下面的多級目錄也過濾,等號后面的單詞就是過濾器 --> <value>
<!--如果該路徑的用戶不包含“模塊管理”權限就禁止訪問--> <!-- /system/module/list.do = perms["模塊管理"] userLogin.do /userLogin* = anon mylogiin.jsp /mylogin* = anon --> /index.jsp* = anon /login.jsp* = anon /login* = anon /logout* = anon /css/** = anon /img/** = anon /plugins/** = anon /make/** = anon <!-- --> /** = authc /*.* = authc </value> </property> </bean> <!-- 保證實現了Shiro內部lifecycle函數的bean執行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 生成代理,通過代理進行控制 --> <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> <aop:aspectj-autoproxy proxy-target-class="true"/>
2.1 自定義realm
/** * 自定義reamlm*/ public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private ModuleService moduleService; /** * 授權管理:授權 */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } /** * 身份認證 * 用於驗證輸入的用戶名密碼給,登錄 */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //1.獲取到用戶界面輸入的用戶名和密碼 UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken; //2.獲取用戶出入的用戶名和密碼 String username = upToken.getUsername(); String password = new String(upToken.getPassword()); //3.根據用戶名查詢用戶對象 User user = userService.findByUsername(username); if(user != null) { //第一個參數:安全數據(user對象) //第二個參數:密碼(數據庫密碼) //第三個參數:當前調用realm域的名稱(類名即可) SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName()); return info; } return null; //subject.login()方法的時候會拋出異常 } }
AuthorizingRealm抽象類中被重寫的方法來源
2.2 自定義密碼比較
在spring與shiro的整合文件中已經將該類交給realm域中,所以直接重寫方法doCredentialsMatch即可
/** * 密碼比較器 */ public class CustomCredentialsMatcher extends SimpleCredentialsMatcher { /** * 用戶密碼比較 * 1.對用戶輸入的密碼進行加密 * 2.比較用戶輸入的密碼和數據庫密碼是否一致 * @param token 用戶界面輸入的郵箱和密碼 * @param info 安全數據:用戶對象user * * 111111 + 固定值(加鹽) = xxxxxx */ public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { //1.獲取用戶輸入的密碼 UsernamePasswordToken upToken = (UsernamePasswordToken) token; String loginPassword = new String(upToken.getPassword()); String email = upToken.getUsername(); //2.對登錄密碼進行加密 //加密:使用MD5加密 String md5Paasword = Encrypt.md5(loginPassword, email);//密碼,鹽 //info.getPrincipals();//獲取安全數據,用戶對象 //獲取數據庫密碼 String dbPassword = (String)info.getCredentials(); //true:登錄成功,false:拋出異常 return md5Paasword.equals(dbPassword); } }
2.3 用戶登錄url映射
//用戶登錄 @RequestMapping("/login") public String login(String username,String password) { //1、通過shiro框架提供的SecurityUtils工具類獲取Subject Subject subject = SecurityUtils.getSubject(); //2、構造用戶名密碼的安全對象upToken UsernamePasswordToken upToken = new UsernamePasswordToken(username,password); //3、通過Subject的login()方法將安全對象交給shiro的安全管理器SecurityManager subject.login(upToken); //4、通過shiro獲取用戶對象主體,保存到session User user = (User) subject.getPrincipal(); //獲取完全對象 session.setAttribute("user",user); //5、查詢菜單數據 List<Module> moduleList = moduleService.findModuleByUserid(user.getId()); session.setAttribute("modules",moduleList); return "home/main"; }
》》》shiro的權限管理的注解開發只需要一個注解代碼
/** * RequiresPermissions: * value : 權限名稱(標識) * 如果具備此權限:進入方法 * 不具備此權限:拋出異常 */ @RequiresPermissions("模塊管理") @RequestMapping(value = "/list",name = "查詢所有") public String list(@RequestParam(defaultValue = "1")int page,@RequestParam(defaultValue = "3")int size){ PageInfo info = moduleService.findAll(page,size); request.setAttribute("page",info); return "system/module/module-list"; }
2.4 頁面標簽展示
通過shiro標簽控制頁面按鈕和菜單的顯示
2.4.1 引入標簽庫
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
2.4.2 控制顯示
<shiro:hasPermission name="刪除部門"> <button type="button" class="btn btn-default" title="刪除" onclick='deleteById()'><i class="fa fa-trash-o"></i> 刪除</button> </shiro:hasPermission>
2.4 用戶退出
//退出 @RequestMapping(value = "/logout",name="用戶登出") public String logout(){ SecurityUtils.getSubject().logout(); //登出 return "forward:login.jsp"; }
shiro自動管理session,此處會將session中的用戶信息清除。
shiro獲取當前用戶的用戶名
Subject subject = SecurityUtils.getSubject();
Object principal = subject.getPrincipal();