麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Apache Shiro 學(xué)習(xí)記錄4

2019-11-15 00:38:11
字體:
供稿:網(wǎng)友
Apache Shiro 學(xué)習(xí)記錄4

  今天看了教程的第三章...是關(guān)于授權(quán)的......和以前一樣.....自己也研究了下....我覺得看那篇教程怎么說呢.....總體上是為數(shù)不多的精品教程了吧....但是有些地方確實(shí)是講的太少了....而這些地方又是蠻難的..比如3.5節(jié)Authorizer、PermissionResolver及RolePermissionResolver...可能作者覺得講清楚要花太多的篇幅涉及太多的類吧.....但是我看起來就很不爽0.0....既然提到了就想弄明白.....不然太糾結(jié)了....所以就有了這篇學(xué)習(xí)記錄...記錄我對Shiro授權(quán)的理解

Subject

我是從subject.isPermittedAll("system:view")這里開始研究的...

和我的上一篇學(xué)習(xí)記錄寫到的一樣Subject只是一個(gè)接口,它的實(shí)現(xiàn)類是DelegatingSubject類.

1     public boolean isPermittedAll(String... permissions) {2         return hasprincipals() && securityManager.isPermittedAll(getPRincipals(), permissions);3     }

授權(quán)和認(rèn)證太像啦,這里subject其實(shí)也是委托securityManager來具體處理的(第2行).

SecurityManager

securityManager的實(shí)現(xiàn)類是DefaultSecurityManager...DefaultSecurityManager的N層父類AuthorizingSecurityManager里有isPermitted方法

1     public boolean isPermittedAll(PrincipalCollection principals, String... permissions) {2         return this.authorizer.isPermittedAll(principals, permissions);3     }

從中可以看出....Shiro的認(rèn)證和授權(quán)真的是太像了...這里授權(quán)是委托授權(quán)器authorizer來做具體的授權(quán),就像我學(xué)習(xí)認(rèn)證那篇文章講的,認(rèn)證是委托authenticator來做一樣.

ModularRealmAuthorizer

我想再吐槽一下.....ModularRealmAuthorizer和ModularRealmAuthenticator真是親兄弟啊......我差點(diǎn)就看錯名字了....

 1     public boolean isPermittedAll(PrincipalCollection principals, String... permissions) { 2         assertRealmsConfigured(); 3         if (permissions != null && permissions.length > 0) { 4             for (String perm : permissions) { 5                 if (!isPermitted(principals, perm)) { 6                     return false; 7                 } 8             } 9         }10         return true;11     }

這里就是把permissions一個(gè)一個(gè)取出來,調(diào)用isPermitted(principals, perm)方法去看看用戶是否有每一個(gè)傳入的權(quán)限perm(第5行)...........

全部包含就是返回true,否則返回false.

那我們就去看看isPermitted方法好了

 1     public boolean isPermitted(PrincipalCollection principals, String permission) { 2         assertRealmsConfigured(); 3         for (Realm realm : getRealms()) { 4             if (!(realm instanceof Authorizer)) continue; 5             if (((Authorizer) realm).isPermitted(principals, permission)) { 6                 return true; 7             } 8         } 9         return false;10     }

從這里(第5行)可以看出其實(shí)ModularRealmAuthorizer是調(diào)用了Realm的isPermitted的....

AuthorizingRealm
 1     public boolean isPermitted(PrincipalCollection principals, String permission) { 2         Permission p = getPermissionResolver().resolvePermission(permission); 3         return isPermitted(principals, p); 4     } 5  6     public boolean isPermitted(PrincipalCollection principals, Permission permission) { 7         AuthorizationInfo info = getAuthorizationInfo(principals); 8         return isPermitted(permission, info); 9     }10 11     private boolean isPermitted(Permission permission, AuthorizationInfo info) {12         Collection<Permission> perms = getPermissions(info);13         if (perms != null && !perms.isEmpty()) {14             for (Permission perm : perms) {15                 if (perm.implies(permission)) {16                     return true;17                 }18             }19         }20         return false;21     }

那么Realm又是怎么處理的呢?

在第一個(gè)方法中調(diào)用PermissionResolver去把要驗(yàn)證的字符串的permission轉(zhuǎn)化成了實(shí)實(shí)在在的Permission對象...這是很重要的一步(但是PermissionResolver在第三個(gè)方法中也有用到,所以這里就不提了)....

然后再第二個(gè)方法中根據(jù)傳入的principals調(diào)用Realm的getAuthorizationInfo(principals)得到AuthorizationInfo ....這里大家一定很熟悉...因?yàn)樽约簩慠ealm的話一定會去覆蓋這個(gè)getAuthorizationInfo方法..返回的AuthenorizationInfo里可以得到用戶的權(quán)限...只不過也是字符串形式......

然后就到了第三個(gè)方法....第12行,把info再轉(zhuǎn)化成Permission對象的集合...然后遍歷這個(gè)集合,去和傳入的permission比較,看看用戶的permission是否包含(implies)傳入的permission....

 1     private Collection<Permission> getPermissions(AuthorizationInfo info) { 2         Set<Permission> permissions = new HashSet<Permission>(); 3  4         if (info != null) { 5             Collection<Permission> perms = info.getObjectPermissions(); 6             if (!CollectionUtils.isEmpty(perms)) { 7                 permissions.addAll(perms); 8             } 9             perms = resolvePermissions(info.getStringPermissions());10             if (!CollectionUtils.isEmpty(perms)) {11                 permissions.addAll(perms);12             }13 14             perms = resolveRolePermissions(info.getRoles());15             if (!CollectionUtils.isEmpty(perms)) {16                 permissions.addAll(perms);17             }18         }19 20         if (permissions.isEmpty()) {21             return Collections.emptySet();22         } else {23             return Collections.unmodifiableSet(permissions);24         }25     }

AuthorizationInfo對象(包含用戶字符串形式的權(quán)限)是如何提取出Permission對象的呢?

從上面的方法可以看出權(quán)限是來自3個(gè)方法和合并..info.getObjectPermissions().....resolvePermissions(info.getStringPermissions())和resolveRolePermissions(info.getRoles())....

第一個(gè)方法info.getObjectPermissions()我也不知道它是做啥的....看了源文檔的注釋還是不懂(%>_<%)......我Shiro也僅僅只寫過一個(gè)demo.......實(shí)在是不了解......

第二個(gè)方法resolvePermissions(info.getStringPermissions())很重要..要提到WildcardPermissionResolver和WildcardPermission....等會再說....

第三個(gè)方法resolveRolePermissions(info.getRoles())我覺得是個(gè)預(yù)留的方法....要用到RolePermissionResolver接口的子類來做具體的處理....但是Shiro沒有提供任何實(shí)現(xiàn)...大家可以去看看教程...開濤哥的教程里有他的實(shí)現(xiàn).....我看了下源文檔的注釋....以我英語6級500都不到的渣渣功力來解讀的話(=.=)大致意思就是說有些時(shí)候只能獲取到subject的role,但是沒有permission,這個(gè)時(shí)候用RolePermissionResolver可以根據(jù)role解讀出permission...嗯....大致就是這么個(gè)意思...錯了別打我....Σ( ° △ °|||)︴

然后重點(diǎn)自然就是第二個(gè)方法resolvePermissions(info.getStringPermissions())啦....

 1     private Collection<Permission> resolvePermissions(Collection<String> stringPerms) { 2         Collection<Permission> perms = Collections.emptySet(); 3         PermissionResolver resolver = getPermissionResolver(); 4         if (resolver != null && !CollectionUtils.isEmpty(stringPerms)) { 5             perms = new LinkedHashSet<Permission>(stringPerms.size()); 6             for (String strPermission : stringPerms) { 7                 Permission permission = getPermissionResolver().resolvePermission(strPermission); 8                 perms.add(permission); 9             }10         }11         return perms;12     }

那么Shiro是如何把String的permission轉(zhuǎn)化成實(shí)實(shí)在在的Permission對象的呢?

那就要用到PermissionResolver 的resolvePermission方法了(從上面第7行可以看出)...

WildcardPermissionResolver

WildcardPermissionResolver在Shiro里是PermissionResolver 的默認(rèn)實(shí)現(xiàn)....

看看這個(gè)類名真是高大上...但是其實(shí)代碼超級短....

 1 public class WildcardPermissionResolver implements PermissionResolver { 2  3     /** 4      * Returns a new {@link WildcardPermission WildcardPermission} instance constructed based on the specified 5      * <tt>permissionString</tt>. 6      * 7      * @param permissionString the permission string to convert to a {@link Permission Permission} instance. 8      * @return a new {@link WildcardPermission WildcardPermission} instance constructed based on the specified 9      *         <tt>permissionString</tt>10      */11     public Permission resolvePermission(String permissionString) {12         return new WildcardPermission(permissionString);13     }14 }

就是返回new了一個(gè)WildcardPermission僅此而已....

WildcardPermission
1     public WildcardPermission(String wildcardString) {2         this(wildcardString, DEFAULT_CASE_SENSITIVE);3     }4 5     public WildcardPermission(String wildcardString, boolean caseSensitive) {6         setParts(wildcardString, caseSensitive);7     }

構(gòu)造方法主要就是調(diào)用了setParts方法....另外稍微提一下....DEFAULT_CASE_SENSITIVE默認(rèn)是false....那就是不區(qū)分字符串權(quán)限大小寫咯~(system:view和System:vIew是一會事情)

 1     protected void setParts(String wildcardString, boolean caseSensitive) { 2         if (wildcardString == null || wildcardString.trim().length() == 0) { 3             throw new IllegalArgumentException("Wildcard string cannot be null or empty. Make sure permission strings are properly formatted."); 4         } 5  6         wildcardString = wildcardString.trim(); 7  8         List<String> parts = CollectionUtils.asList(wildcardString.split(PART_DIVIDER_TOKEN)); 9 10         this.parts = new ArrayList<Set<String>>();11         for (String part : parts) {12             Set<String> subparts = CollectionUtils.asSet(part.split(SUBPART_DIVIDER_TOKEN));13             if (!caseSensitive) {14                 subparts = lowercase(subparts);15             }16             if (subparts.isEmpty()) {17                 throw new IllegalArgumentException("Wildcard string cannot contain parts with only dividers. Make sure permission strings are properly formatted.");18             }19             this.parts.add(subparts);20         }21 22         if (this.parts.isEmpty()) {23             throw new IllegalArgumentException("Wildcard string cannot contain only dividers. Make sure permission strings are properly formatted.");24         }25     }

那么setParts方法做了些什么呢?

這個(gè)方法主要就是為WildcardPermission的成員域List<Set<String>> parts去賦值....我們來看看分隔符....

protected static final String WILDCARD_TOKEN = "*"; protected static final String PART_DIVIDER_TOKEN = ":"; protected static final String SUBPART_DIVIDER_TOKEN = ",";

然后大家再看代碼應(yīng)該就沒什么問題了...這個(gè)代碼我覺得沒啥好說的...我就舉幾個(gè)例子吧...可能更直觀點(diǎn)....

如果用戶的字符串權(quán)限是"system:user:create,view"

那么parts這個(gè)成員域List的size是3.第一個(gè)set包含system...第二個(gè)set包含user....第三個(gè)set的size是2,包含create和view

構(gòu)造方法和setParts就做了這些事情! 其實(shí)一點(diǎn)也不多....

好了...現(xiàn)在要檢測的傳入的字符串權(quán)限被轉(zhuǎn)化成了Permission對象....用戶擁有的字符串權(quán)限也轉(zhuǎn)化成了Permission對象....那么如何判斷用戶是否有傳入的權(quán)限呢?

在前面AuthorizingRealm那小節(jié)里我看看到了是調(diào)用perm.implies(permission)來判斷是否包含的....

請注意..perm是用戶的權(quán)限...permission是傳入要檢測的權(quán)限...

我們來看看implies方法吧....

 1     public boolean implies(Permission p) { 2         // By default only supports comparisons with other WildcardPermissions 3         if (!(p instanceof WildcardPermission)) { 4             return false; 5         } 6  7         WildcardPermission wp = (WildcardPermission) p; 8  9         List<Set<String>> otherParts = wp.getParts();10 11         int i = 0;12         for (Set<String> otherPart : otherParts) {13             // If this permission has less parts than the other permission, everything after the number of parts contained14             // in this permission is automatically implied, so return true15             if (getParts().size() - 1 < i) {16                 return true;17             } else {18                 Set<String> part = getParts().get(i);19                 if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {20                     return false;21                 }22                 i++;23             }24         }25 26         // If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards27         for (; i < getParts().size(); i++) {28             Set<String> part = getParts().get(i);29             if (!part.contains(WILDCARD_TOKEN)) {30                 return false;31             }32         }33 34         return true;35     }

代碼就這么點(diǎn)...但是解釋起來可能要很多篇幅....所以我還是覺得舉例子比較快......其實(shí)這個(gè)方法就是比較2個(gè)Permission的parts部分....

比較是一部分一部分進(jìn)行的...先List[0]和List[0]比較(第一個(gè)for的第一次循環(huán))...再List[1]和List[1]比較(第一個(gè)for的第二次循環(huán))....

比如用戶權(quán)限是"*:user,admin:view" 傳入要檢測的權(quán)限是"system:guest:view"

第一個(gè)for的第一輪比較...看代碼第19行....因?yàn)橛脩魀arts的[0]是* !part.contains(WILDCARD_TOKEN)是false..所以繼續(xù)下一輪for循環(huán)...意思就是*肯定包含system

然后進(jìn)入for的第二輪!part.contains(WILDCARD_TOKEN)是true..所以要看!part.containsAll(otherPart)...

變量part是字符串user和admin的集合...otherPart是字符串guest的集合..!part.containsAll(otherPart)返回是true..所以if成立...所以return false..即用戶是不包含傳入檢測的權(quán)限的(當(dāng)然這里其實(shí)沒有這么快就能得出這個(gè)結(jié)論..ModularRealmAuthorizer中如果有多個(gè)realm,要所有realm都返回false才能判斷用戶沒有這個(gè)權(quán)限..因?yàn)槌绦蚩赡軙渲枚鄠€(gè)Realm...多個(gè)Realm可能會給一個(gè)用戶取到不同的權(quán)限...所以每個(gè)Realm都要檢測過來才知道用戶到底包不包含傳入要檢測的權(quán)限...這個(gè)道理蠻簡單的..大家都懂的..我就是稍微提醒一下..我只是假設(shè)我這里就配置了一個(gè)realm.....哈哈)...

看了這個(gè)implies方法的流程...我想大家也能明白為什么user:*是能匹配user:view:123而*:view不能匹配system:user:view的道理吧....

因?yàn)樵谟脩魴?quán)限長度m小于傳入權(quán)限長度n的時(shí)候,implies方法的第一個(gè)for最多做m次就能知道返回是false還是true了..后面的n-m次比較是不會做的...

而用戶權(quán)限長度m大于傳入權(quán)限長度n的時(shí)候,先做implies方法的第一個(gè)for的n次比較,如果還是沒結(jié)果...再做第2個(gè)for..檢測用戶權(quán)限patrs[n-m]到parts[m-1]的部分..這些部分只要有任意一個(gè)不是*那就說明用戶不具有傳入待檢測的權(quán)限...

以上就是我今天對Shiro授權(quán)的理解了吧....


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产亚洲精品久久午夜玫瑰园 | 久久久日韩av免费观看下载 | 在线看毛片的网站 | 色综合精品 | 91精品国产91久久久久久蜜臀 | 成人爱爱电影 | 天天草天天爱 | 久久久久.com | 精品成人免费一区二区在线播放 | 欧美jizzhd极品欧美 | 高清视频一区二区 | 91精品国产91久久久 | 色播久久 | 九九热这里只有精品8 | 国内xxxx乱子另类 | 色综av | www国产网站 | 国产精品久久久久久238 | 999久久久久久 | 2021国产精品视频 | 欧美日韩中文字幕在线 | 成人性视频免费网站下载软件 | 久久99精品久久 | 精品国产一区在线 | 特级黄色影院 | 中文字幕伦乱 | 亚洲国产中文字幕 | 一级美女大片 | 欧美高清视频一区 | 国产乱淫av片免费 | 国产乱淫av片免费观看 | av在线播放地址 | 久久午夜神器 | 亚洲午夜精选 | 小视频在线看 | 9999免费视频 | 日韩黄色片在线观看 | 欧洲精品久久久 | 亚洲精品xxx | 免费在线观看毛片视频 | 一级尻逼视频 |