SpringBoot與Shiro整合權限管理實戰
作者 : Stanley 羅昊
【轉載請注明出處和署名,謝謝!】
*觀看本文章需要有一定SpringBoot整合經驗*
Shiro框架簡介
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。使用Shiro的易於理解的API,可以快速、輕松地獲得任何應用程序,
從最小的移動應用程序到最大的網絡和企業應用程序。
分析Shiro的核心API
其實,Shiro的核心類有三個,分別是:
1.Subject:這個類呢,我們稱之當前用戶的主體,這個用戶的主體包含了登陸、注銷等等的一些方法,還有一些判斷授權的一些方法;
2.SecurityManager:這個名稱翻譯過來就是,安全管理器的意思;
3.Realm:這個Realm呢其實我們Shiro去鏈接數據庫的一個橋梁,因為,我們的程序需要去操作數據庫去獲取一些用戶的信息,這些操作都需要Realm去完成;
這個三個API呢,都存在一些關系,比如.SecurityManager是需要去關聯我們的Realm,Subject是需要把操作交給我們的SecurityManager,總結下來就是,Subject是需要去管理我們的SecurityManager,而SecurityManager去關聯我們的Realm;
以上就是對Shiro的核心API進行的一些分析;
分析完之后,我們接下來就直接用SpringBoot與Shiro的整合,我們來看下它整合的關鍵步驟
SpringBoot整合Shiro
那么這個整合首先第一步需要導入Shiro的依賴;
【因為我用的是Gradle,所以僅展示Gradle用法】
1.修改.gradle文件,添加以下依賴
//Thymeleaf模板引擎,因為我用模板引擎所以我添加了此依賴 compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE' //Shiro compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.4.0' compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0' // https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'
2.編寫Shiro的配置類
配置類需要三樣API,分別是:
/** * 創建ShiroFilterFactoryBean * shiro過濾bean */ /** * 創建DefaultWebSecurityManager */ /** * 創建Realm */
如圖:
3.自定義Realm類
因為我們需要在配置類中創建出Realm對象,所以我們需要建一個名為Realm的類:
創建后,需要繼承一個方法,這個方法是Shiro提供的:
/** * 自定義Realm */ public class UserRealm extends AuthorizingRealm { //執行授權邏輯 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } //執行認證邏輯 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { return null; }
4.在配置類中new出Realm
Shiro配置配置類
package com.lh.shiroStudy.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * Shiro配置類 */ //@Configuration,聲明本類是一個配置類 @Configuration public class ShiroConfig { /** * 創建ShiroFilterFactoryBean * shiro過濾bean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加Shiro過濾器 /** * Shiro內置過濾器,可以實現權限相關的攔截器 * 常用的過濾器: * anon: 無需認證(登錄)可以訪問 * authc: 必須認證才可以訪問 * user: 如果使用rememberMe功能可以直接訪問 * perms: 該資源必須得到資源權限才可以訪問 * role: 該資源必須得到角色權限才可以訪問 */ Map<String,String>filterMap = new LinkedHashMap<String, String>(); //左邊編寫攔截路徑 filterMap.put("/add","authc"); filterMap.put("/update","authc"); filterMap.put("/testThymeleaf","authc"); //授權過濾器 //注意:當前授權攔截后,shiro會自動跳轉未授權頁面 filterMap.put("/add","perms[user:add]"); //修改跳轉的登陸頁面 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //轉跳至未授權頁面【友好提示】 shiroFilterFactoryBean.setUnauthorizedUrl("/aaaaaa");//懶省事所以沒有aaaa這個頁面,如果需要,請在Contoller中添加 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 創建DefaultWebSecurityManager */ @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); return securityManager; } /** * 創建Realm */ @Bean(name = "UserRealm") public UserRealm getRealm(){ return new UserRealm(); } }
Realm類
package com.lh.shiroStudy.shiro; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * 自定義Realm */ public class UserRealm extends AuthorizingRealm { //執行授權邏輯 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //給資源進行授權 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //添加資源的授權字符串 //info.addStringPermission("user:add"); //到數據庫查詢當前登陸用戶的授權字符串 /** * <!-演示狀態-!> * 獲取當前用戶 * Subject subject = SecurityUtils.getSubject(); * User user = (User)subject.getPrincipal(); * User dbUser = userService.findById(id) * info.addStringPermission(dbUser.getPerms()); * </!-演示狀態-!> */ System.out.println("執行授權邏輯"); return null; } //執行認證邏輯 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { System.out.println("執行認證邏輯"); //假設數據庫賬號與密碼是如下 String username = "admin"; String password = "123456"; /** * 編寫Shiro判斷邏輯,比對用戶名和密碼 */ //1.判斷用戶名 UsernamePasswordToken token =(UsernamePasswordToken)arg0; //User user = userService.findByName(token.getUsername()); if (user == null){ //用戶名不存在 return null;//如果返回null,Shiro底層會拋出UnknowAccountException } //2.判斷密碼 /** * 有三個參數 * 1.需要返回給login * 2.是數據庫的密碼,將數據庫密碼返回,Shiro會自動判斷 * 3.是Shiro的名字 */ return new SimpleAuthenticationInfo(user,password,""); } }