(4)shiro多個realm
shiro支援多個realm,當設定多個realm的時候,shiro的認證和授權的步驟是怎樣的呢。
多個realm認證原理:
發現需要在執行認證的時候,需要策略來處理多個realm存在的情況。預設實現類有三個策略:
1. AtLeastOneSuccessfulStrategy :如果一個(或更多)Realm 驗證成功,則整體的嘗試被認為是成功的。如果沒有一個驗證成功,則整體嘗試失敗。
2. FirstSuccessfulStrategy 只有第一個成功地驗證的Realm 返回的資訊將被使用。後面的realm會被忽略,如果一個都沒有成功則失敗。
3. AllSucessfulStrategy 為了整體的嘗試成功,所有配置的Realm 必須驗證成功。如果沒有一個驗證成功,則整體嘗試失敗。
ModularRealmAuthenticator 預設的是AtLeastOneSuccessfulStrategy
多個realm授權原理:
當shiro判斷是否有對應的角色或者資源的時候,最底層是呼叫Authenticator的doAuthenticate方法。
下面是Authenticator的一個實現類(ModularRealmAuthenticator)當有多個realms的時候執行的步驟:
得到總結:只要有一個realm裡面有這個角色或者資源就代表有這個許可權
程式碼測試
1,新增一個realm2,無論如何都是通過的,返回的principal固定為test(自己可以根據業務需要,為當前登入的使用者設定別的身份)
public class MyRealm2 extends AuthorizingRealm { //認證資訊, @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String password = newString(upToken.getPassword()); //模擬使用者名稱密碼是否正確 return new SimpleAuthenticationInfo("test",password,getName()); } //授權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //獲取使用者名稱 String username = (String)getAvailablePrincipal(principals); //模擬從資料庫查詢出來對應的角色和許可權 Set<String> roles = new HashSet<String>(); roles.add("role_3"); roles.add("role_4"); Set<String> permissions = new HashSet<String>(); permissions.add("user:update"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; }
2配置檔案
myrealm=com.nfcm.shiro.Realm.MyRealm myrealm2=com.nfcm.shiro.Realm.MyRealm2 #設定策略,必須所有的realm都通過 authcStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy #配置認證器 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator #將驗證器和策略關聯起來 authenticator.authenticationStrategy=$authcStrategy #注入認證器 securityManager.authenticator=$authenticator #設定realm,這個要最後設定,如果後設置認證器或者授權器,則裡面的realms都是空的 securityManager.realms=$myrealm,$myrealm2
3.測試程式碼
ShiroUtils.login("classpath:shiro-myrealm2.ini","zhang","123456"); Subject subject = SecurityUtils.getSubject(); List<String> principals =subject.getPrincipals().asList(); for (String principal:principals) { System.out.println(principal); } System.out.println(subject.getPrincipals().getPrimaryPrincipal()); //是否通過認證 System.out.println(subject.isAuthenticated()); //是否有role1角色 System.out.println(subject.hasRole("role_1")); //realm2裡面的角色 System.out.println(subject.hasRole("role_3")); System.out.println(subject.isPermitted("user:create")); //realm2裡面的資源 System.out.println(subject.isPermitted("user:update"));
最後輸出結果:
zhang
test
zhang
true
true
true
true
true
getPrimaryPrincipal方法獲取的是第一個realm裡面的身份。
subject.getPrincipals().fromRealm("myrealm2")可以獲取指定的realm裡面的身份資訊,返回的是一個集合,獲取第一個即可。
github程式碼地址
https://github.com/cmniefei/shiroparent