認證流程
1. 首先調用Subject.login(token)進行登錄,其會自動委托給Security Manager,調用之前必須通過
SecurityUtils. setSecurityManager()設置;
2. SecurityManager負責真正的身份驗證邏輯;它會委托給Authenticator進行身份驗證;
3. Authenticator才是真正的身份驗證者,Shiro API中核心的身份認證入口點,此處可以自定義插入自己的實
現;
4. Authenticator可能會委托給相應的AuthenticationStrategy進行多Realm身份驗證,默認
ModularRealmAuthenticator會調用AuthenticationStrategy進行多Realm身份驗證;
5. Authenticator會把相應的token傳入Realm,從Realm獲取身份驗證信息,如果沒有返回/拋出異常表示身份
驗證失敗了。此處可以配置多個Realm,將按照相應的順序及策略進行訪問。
授權流程
1. 首先調用Subject.isPermitted/hasRole接口,其會委托給SecurityManager,而SecurityManager接着會委托
給Authorizer;
2. Authorizer是真正的授權者,如果我們調用如isPermitted(“user:view”),其首先會通過PermissionResolver
把字符串轉換成相應的Permission實例;
3. 在進行授權之前,其會調用相應的Realm獲取Subject相應的角色/權限用於匹配傳入的角色/權限;
4. Authorizer會判斷Realm的角色/權限是否和傳入的匹配,如果有多個Realm,會委托給
ModularRealmAuthorizer進行循環判斷,如果匹配如isPermitted/hasRole會返回true,否則返回false表示
授權失敗。
1.自定義realms 類
必須繼承 AuthorizingRealm 抽象類

package com.zhao; 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; import java.util.ArrayList; import java.util.List; /** * 自定義realms 對象 * 繼承 AuthorizingRealm */ public class RealmDemo extends AuthorizingRealm { /** * 設置 RealmDemo 名字 ,自定義realms 對象 過多時避免重復 * @param name */ @Override public void setName(String name) { super.setName("realmDemo"); } /** * 授權 * 獲取到用戶的授權數據(用戶的權限數據) * 根據認證的用戶 獲取到他的權限信息 * @param principals 包含了所有的已認證的安全數據 * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println(" 授權 AuthorizationInfo "); //1.獲取安全數據 username ,有可能是用戶id String primaryPrincipal = (String)principals.getPrimaryPrincipal(); //2.根據 username 或者id查詢用戶 //3.查詢用戶的角色 和權限信息 //權限 List<String> perms =new ArrayList<>(); perms.add("user:save"); perms.add("user:find"); //角色 List<String> roles =new ArrayList<>(); roles.add("ordinary"); roles.add("admin"); //4.構造返回 SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); //設置權限集合 info.addStringPermissions(perms); //設置角色集合 info.addRoles(roles); return info; } /** * 認證 * 根據用戶名密碼進行登錄,登錄之后將用戶數據進行保存 * 認證的目的,比較用戶名和密碼是否與數據庫中的一致 * 將安全數據存入到shiro進行保管 * @param authenticationToken 登錄構造的 UsernamePasswordToken * @return AuthenticationInfo 授權數據 * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println(" 認證 AuthenticationInfo "); //1. 構造 UsernamePasswordToken UsernamePasswordToken uptoken=(UsernamePasswordToken)authenticationToken; //2.獲取輸入的用戶名密碼 String username = uptoken.getUsername(); String password = new String(uptoken.getPassword()); //3.根據用戶名查詢數據 //4.比較密碼和數據庫中的密碼是否一致(密碼可能需要加密) if(username.equals("張三")&&password.equals("123456")){ //5.成功 向 shiro存入數據 /** * *@param principal與指定領域關聯的“primary”主體。 安全數據 * *@param credentials驗證給定主體的憑據。 密碼 * *@param realmName從中獲取主體和憑據的域。 當前realm 名稱 getName() 獲取到的是當前realm的名稱 ,他的父類方法 */ SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,getName()); return simpleAuthenticationInfo; }else { //6.失敗 返回null 或者拋出 自定義的異常 return null; } } }
2.配置文件

[main] permRealm=com.zhao.RealmDemo #注冊realm到securityManager securityManager.realms=$permRealm
3.測試

package com.zhao.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Before; import org.junit.Test; public class ShiroTest3 { @Before public void init(){ // 1.根據配置文件shiroDemo.ini 文件 創建 SecurityManagerFactor Factory<SecurityManager> factory= new IniSecurityManagerFactory("classpath:shiroDemoRealm.ini"); //2.通過工廠獲取SecurityManager SecurityManager securityManager = factory.getInstance(); //* 3.將SecurityManager綁定到當前運行環境 SecurityUtils.setSecurityManager(securityManager); } /** * 測試用戶登錄 * 用戶認證 * 1.根據配置文件shiroDemo.ini 文件 創建 SecurityManagerFactor * 2.通過工廠獲取SecurityManager * 3.將SecurityManager綁定到當前運行環境 * 4.從當前環境中構造subject * 5.構造shiro登陸的數據 * 6.主題登錄 */ @Test public void login1(){ //* 4.從當前環境中構造subject Subject subject = SecurityUtils.getSubject(); // * 5.構造用戶認證的數據 // String userName="lisi"; // String password = "10086"; String userName="張三"; String password = "123456"; UsernamePasswordToken token =new UsernamePasswordToken(userName,password); // * 6.主題登錄 //執行 login1--》realm 域中的認證方法 subject.login(token); //登錄之后完成授權 ,是否具有某個角色 System.out.println(subject.hasRole("admin")); //是否有admin 這個角色 System.out.println(subject.hasRole("root")); //是否有root 這個角色 System.out.println(subject.isPermitted("user:save"));// 是否有 user:save 這個權限 } }
參考視頻 :https://www.bilibili.com/video/av75572951?p=108