亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Apache Shiro 學習記錄4

2019-11-15 00:38:11
字體:
來源:轉載
供稿:網友
Apache Shiro 學習記錄4

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

Subject

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

和我的上一篇學習記錄寫到的一樣Subject只是一個接口,它的實現類是DelegatingSubject類.

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

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

SecurityManager

securityManager的實現類是DefaultSecurityManager...DefaultSecurityManager的N層父類AuthorizingSecurityManager里有isPermitted方法

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

從中可以看出....Shiro的認證和授權真的是太像了...這里授權是委托授權器authorizer來做具體的授權,就像我學習認證那篇文章講的,認證是委托authenticator來做一樣.

ModularRealmAuthorizer

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

 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一個一個取出來,調用isPermitted(principals, perm)方法去看看用戶是否有每一個傳入的權限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行)可以看出其實ModularRealmAuthorizer是調用了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又是怎么處理的呢?

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

然后再第二個方法中根據傳入的principals調用Realm的getAuthorizationInfo(principals)得到AuthorizationInfo ....這里大家一定很熟悉...因為自己寫Realm的話一定會去覆蓋這個getAuthorizationInfo方法..返回的AuthenorizationInfo里可以得到用戶的權限...只不過也是字符串形式......

然后就到了第三個方法....第12行,把info再轉化成Permission對象的集合...然后遍歷這個集合,去和傳入的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對象(包含用戶字符串形式的權限)是如何提取出Permission對象的呢?

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

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

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

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

然后重點自然就是第二個方法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轉化成實實在在的Permission對象的呢?

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

WildcardPermissionResolver

WildcardPermissionResolver在Shiro里是PermissionResolver 的默認實現....

看看這個類名真是高大上...但是其實代碼超級短....

 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了一個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     }

構造方法主要就是調用了setParts方法....另外稍微提一下....DEFAULT_CASE_SENSITIVE默認是false....那就是不區分字符串權限大小寫咯~(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方法做了些什么呢?

這個方法主要就是為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 = ",";

然后大家再看代碼應該就沒什么問題了...這個代碼我覺得沒啥好說的...我就舉幾個例子吧...可能更直觀點....

如果用戶的字符串權限是"system:user:create,view"

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

構造方法和setParts就做了這些事情! 其實一點也不多....

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

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

請注意..perm是用戶的權限...permission是傳入要檢測的權限...

我們來看看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     }

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

比較是一部分一部分進行的...先List[0]和List[0]比較(第一個for的第一次循環)...再List[1]和List[1]比較(第一個for的第二次循環)....

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

第一個for的第一輪比較...看代碼第19行....因為用戶parts的[0]是* !part.contains(WILDCARD_TOKEN)是false..所以繼續下一輪for循環...意思就是*肯定包含system

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

變量part是字符串user和admin的集合...otherPart是字符串guest的集合..!part.containsAll(otherPart)返回是true..所以if成立...所以return false..即用戶是不包含傳入檢測的權限的(當然這里其實沒有這么快就能得出這個結論..ModularRealmAuthorizer中如果有多個realm,要所有realm都返回false才能判斷用戶沒有這個權限..因為程序可能會配置多個Realm...多個Realm可能會給一個用戶取到不同的權限...所以每個Realm都要檢測過來才知道用戶到底包不包含傳入要檢測的權限...這個道理蠻簡單的..大家都懂的..我就是稍微提醒一下..我只是假設我這里就配置了一個realm.....哈哈)...

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

因為在用戶權限長度m小于傳入權限長度n的時候,implies方法的第一個for最多做m次就能知道返回是false還是true了..后面的n-m次比較是不會做的...

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

以上就是我今天對Shiro授權的理解了吧....


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
www.欧美视频| 亚洲人成绝费网站色www| 热门国产精品亚洲第一区在线| 国产精品对白刺激| 国产精品男人的天堂| www.久久撸.com| 亚洲天堂视频在线观看| 亚洲欧洲一区二区三区久久| 国产99视频精品免视看7| 亚洲欧美中文日韩在线| 欧美精品电影免费在线观看| 日韩在线小视频| 欧美激情第三页| 91久久久久久久久| 成人网页在线免费观看| 国产精品羞羞答答| 亚洲成人精品av| 九九热精品视频| 福利视频一区二区| 久久精品免费播放| 日韩中文在线中文网在线观看| 亚洲自拍偷拍在线| 91精品国产九九九久久久亚洲| 免费成人高清视频| 狠狠久久亚洲欧美专区| 日韩欧美国产高清91| 91欧美激情另类亚洲| 91免费国产网站| 国产婷婷色综合av蜜臀av| 欧美一级大片视频| 在线亚洲欧美视频| 91久久精品国产91久久| 亚洲天堂成人在线视频| 91在线免费观看网站| 91精品视频免费观看| 中文字幕精品www乱入免费视频| 91久久夜色精品国产网站| 亚洲成人久久久| 久久久女女女女999久久| 国内精品免费午夜毛片| 7m第一福利500精品视频| 欧美大片免费观看在线观看网站推荐| 久久精品99久久久香蕉| 亚洲日韩欧美视频| 亚洲韩国青草视频| 日韩视频免费大全中文字幕| 欧美亚洲第一区| 国产69精品久久久| 亚洲香蕉在线观看| 精品偷拍一区二区三区在线看| 亚洲欧洲av一区二区| 亚洲精品国产精品自产a区红杏吧| 午夜精品久久久久久久男人的天堂| 黑丝美女久久久| 红桃视频成人在线观看| 欧美电影免费观看网站| 欧美丰满老妇厨房牲生活| 亚洲第一视频网| 欧美一级视频一区二区| 精品国产一区二区三区久久久狼| 国产精品视频中文字幕91| 国产精品国模在线| 国产一区二区久久精品| 欧美成人三级视频网站| 国产成人亚洲精品| 欧美日韩激情视频8区| 欧美第一页在线| 欧美日韩第一视频| 国产在线久久久| 一区二区欧美激情| 亚洲第一视频网站| 欧美视频专区一二在线观看| 亚洲专区在线视频| 欧美xxxx18国产| 91在线免费观看网站| 精品国产户外野外| 亚洲欧洲在线看| 美女福利视频一区| 亚洲成人1234| 神马久久桃色视频| 日韩成人激情影院| 在线观看国产欧美| 欧美孕妇性xx| 欧美成人激情图片网| 午夜精品久久久久久久久久久久| 欧美电影在线免费观看网站| 91av在线精品| 自拍偷拍亚洲在线| 欧美国产日韩在线| 欧美在线激情网| 狠狠综合久久av一区二区小说| 中文字幕精品久久| 在线播放国产精品| 欧美剧在线观看| 亚洲人成免费电影| 亚洲精品免费一区二区三区| 国产精品入口日韩视频大尺度| 91福利视频网| 国产网站欧美日韩免费精品在线观看| 日韩av影院在线观看| 欧美一级电影在线| 亚洲视频999| 成人免费视频97| 日韩在线播放一区| 成人免费看片视频| 亚洲成人激情在线观看| 欧美日韩加勒比精品一区| 成人av番号网| 午夜精品久久久久久久久久久久久| 欧美放荡办公室videos4k| 蜜臀久久99精品久久久无需会员| 亚洲在线免费观看| 中文字幕亚洲欧美日韩高清| 亚洲毛茸茸少妇高潮呻吟| 欧美性生交大片免网| 国产日韩中文字幕| 欧美丰满片xxx777| 国产精品一区专区欧美日韩| 亚洲人成在线一二| 国产一区二区三区在线免费观看| 亚洲一二三在线| 91精品国产一区| 热99在线视频| 97婷婷涩涩精品一区| 2024亚洲男人天堂| 自拍偷拍亚洲在线| 国产精品男女猛烈高潮激情| 国产综合视频在线观看| 欧美自拍视频在线观看| 九九热99久久久国产盗摄| 国产91精品久| 亚洲久久久久久久久久| 久久精品91久久香蕉加勒比| 疯狂做受xxxx高潮欧美日本| 成人在线观看视频网站| 国产盗摄xxxx视频xxx69| 成人激情春色网| 国产精品黄视频| 欧美高清视频在线| 日韩禁在线播放| 亚洲欧美日韩在线高清直播| 亚洲级视频在线观看免费1级| 色综合男人天堂| 成人天堂噜噜噜| 亚洲精品v天堂中文字幕| 久久免费视频这里只有精品| 91精品久久久久久久久久| 欧美久久精品一级黑人c片| 国产99久久精品一区二区永久免费| 91tv亚洲精品香蕉国产一区7ujn| 亚洲精品美女网站| 亚洲欧洲日产国码av系列天堂| 中文字幕一区电影| www.亚洲男人天堂| 日韩高清欧美高清| 亚洲欧美日韩另类| 欧美亚洲第一页| 欧美日韩aaaa| 亚洲精品久久久久久久久久久久久| 成人h猎奇视频网站| 欧美日韩国产精品一区二区三区四区| 日韩精品中文字幕久久臀| 国产精品99蜜臀久久不卡二区| 欧美裸体xxxx|