小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

第三章 授權(quán)

 muyable 2015-02-13

 

目錄貼: 跟我學(xué)Shiro目錄貼

 

授權(quán),也叫訪問控制,即在應(yīng)用中控制誰能訪問哪些資源(如訪問頁面/編輯數(shù)據(jù)/頁面操作等)。在授權(quán)中需了解的幾個關(guān)鍵對象:主體(Subject)、資源(Resource)、權(quán)限(Permission)、角色(Role)。

主體

主體,即訪問應(yīng)用的用戶,在Shiro中使用Subject代表該用戶。用戶只有授權(quán)后才允許訪問相應(yīng)的資源。

資源

在應(yīng)用中用戶可以訪問的任何東西,比如訪問JSP頁面、查看/編輯某些數(shù)據(jù)、訪問某個業(yè)務(wù)方法、打印文本等等都是資源。用戶只要授權(quán)后才能訪問。

權(quán)限

安全策略中的原子授權(quán)單位,通過權(quán)限我們可以表示在應(yīng)用中用戶有沒有操作某個資源的權(quán)力。即權(quán)限表示在應(yīng)用中用戶能不能訪問某個資源,如:

訪問用戶列表頁面

查看/新增/修改/刪除用戶數(shù)據(jù)(即很多時候都是CRUD(增查改刪)式權(quán)限控制)

打印文檔等等。。。

 

如上可以看出,權(quán)限代表了用戶有沒有操作某個資源的權(quán)利,即反映在某個資源上的操作允不允許,不反映誰去執(zhí)行這個操作。所以后續(xù)還需要把權(quán)限賦予給用戶,即定義哪個用戶允許在某個資源上做什么操作(權(quán)限),Shiro不會去做這件事情,而是由實現(xiàn)人員提供。

 

Shiro支持粗粒度權(quán)限(如用戶模塊的所有權(quán)限)和細粒度權(quán)限(操作某個用戶的權(quán)限,即實例級別的),后續(xù)部分介紹。

角色

角色代表了操作集合,可以理解為權(quán)限的集合,一般情況下我們會賦予用戶角色而不是權(quán)限,即這樣用戶可以擁有一組權(quán)限,賦予權(quán)限時比較方便。典型的如:項目經(jīng)理、技術(shù)總監(jiān)、CTO、開發(fā)工程師等都是角色,不同的角色擁有一組不同的權(quán)限。

隱式角色:即直接通過角色來驗證用戶有沒有操作權(quán)限,如在應(yīng)用中CTO、技術(shù)總監(jiān)、開發(fā)工程師可以使用打印機,假設(shè)某天不允許開發(fā)工程師使用打印機,此時需要從應(yīng)用中刪除相應(yīng)代碼;再如在應(yīng)用中CTO、技術(shù)總監(jiān)可以查看用戶、查看權(quán)限;突然有一天不允許技術(shù)總監(jiān)查看用戶、查看權(quán)限了,需要在相關(guān)代碼中把技術(shù)總監(jiān)角色從判斷邏輯中刪除掉;即粒度是以角色為單位進行訪問控制的,粒度較粗;如果進行修改可能造成多處代碼修改。

顯示角色:在程序中通過權(quán)限控制誰能訪問某個資源,角色聚合一組權(quán)限集合;這樣假設(shè)哪個角色不能訪問某個資源,只需要從角色代表的權(quán)限集合中移除即可;無須修改多處代碼;即粒度是以資源/實例為單位的;粒度較細。

 

 

請google搜索“RBAC”和“RBAC新解”分別了解“基于角色的訪問控制”“基于資源的訪問控制(Resource-Based Access Control)”。

 

3.1 授權(quán)方式

Shiro支持三種方式的授權(quán):

 

編程式:通過寫if/else授權(quán)代碼塊完成: 

Java代碼  收藏代碼
  1. Subject subject = SecurityUtils.getSubject();  
  2. if(subject.hasRole(“admin”)) {  
  3.     //有權(quán)限  
  4. else {  
  5.     //無權(quán)限  
  6. }   

 

注解式:通過在執(zhí)行的Java方法上放置相應(yīng)的注解完成: 

Java代碼  收藏代碼
  1. @RequiresRoles("admin")  
  2. public void hello() {  
  3.     //有權(quán)限  
  4. }   

沒有權(quán)限將拋出相應(yīng)的異常;

 

JSP/GSP標(biāo)簽:在JSP/GSP頁面通過相應(yīng)的標(biāo)簽完成: 

Java代碼  收藏代碼
  1. <shiro:hasRole name="admin">  
  2. <!— 有權(quán)限 —>  
  3. </shiro:hasRole>   

后續(xù)部分將詳細介紹如何使用。   

 

3.2 授權(quán)

基于角色的訪問控制(隱式角色)

 

1、在ini配置文件配置用戶擁有的角色(shiro-role.ini) 

Java代碼  收藏代碼
  1. [users]  
  2. zhang=123,role1,role2  
  3. wang=123,role1   

規(guī)則即:“用戶名=密碼,角色1,角色2”,如果需要在應(yīng)用中判斷用戶是否有相應(yīng)角色,就需要在相應(yīng)的Realm中返回角色信息,也就是說Shiro不負責(zé)維護用戶-角色信息,需要應(yīng)用提供,Shiro只是提供相應(yīng)的接口方便驗證,后續(xù)會介紹如何動態(tài)的獲取用戶角色。

 

2、測試用例(com.github.zhangkaitao.shiro.chapter3.RoleTest) 

Java代碼  收藏代碼
  1. @Test  
  2. public void testHasRole() {  
  3.     login("classpath:shiro-role.ini""zhang""123");  
  4.     //判斷擁有角色:role1  
  5.     Assert.assertTrue(subject().hasRole("role1"));  
  6.     //判斷擁有角色:role1 and role2  
  7.     Assert.assertTrue(subject().hasAllRoles(Arrays.asList("role1""role2")));  
  8.     //判斷擁有角色:role1 and role2 and !role3  
  9.     boolean[] result = subject().hasRoles(Arrays.asList("role1""role2""role3"));  
  10.     Assert.assertEquals(true, result[0]);  
  11.     Assert.assertEquals(true, result[1]);  
  12.     Assert.assertEquals(false, result[2]);  
  13. }   

Shiro提供了hasRole/hasRole用于判斷用戶是否擁有某個角色/某些權(quán)限;但是沒有提供如hashAnyRole用于判斷是否有某些權(quán)限中的某一個。 

 

Java代碼  收藏代碼
  1. @Test(expected = UnauthorizedException.class)  
  2. public void testCheckRole() {  
  3.     login("classpath:shiro-role.ini""zhang""123");  
  4.     //斷言擁有角色:role1  
  5.     subject().checkRole("role1");  
  6.     //斷言擁有角色:role1 and role3 失敗拋出異常  
  7.     subject().checkRoles("role1""role3");  
  8. }   

Shiro提供的checkRole/checkRoles和hasRole/hasAllRoles不同的地方是它在判斷為假的情況下會拋出UnauthorizedException異常。

 

到此基于角色的訪問控制(即隱式角色)就完成了,這種方式的缺點就是如果很多地方進行了角色判斷,但是有一天不需要了那么就需要修改相應(yīng)代碼把所有相關(guān)的地方進行刪除;這就是粗粒度造成的問題。

 

基于資源的訪問控制(顯示角色)

1、在ini配置文件配置用戶擁有的角色及角色-權(quán)限關(guān)系(shiro-permission.ini) 

Java代碼  收藏代碼
  1. [users]  
  2. zhang=123,role1,role2  
  3. wang=123,role1  
  4. [roles]  
  5. role1=user:create,user:update  
  6. role2=user:create,user:delete   

規(guī)則:“用戶名=密碼,角色1,角色2”“角色=權(quán)限1,權(quán)限2”,即首先根據(jù)用戶名找到角色,然后根據(jù)角色再找到權(quán)限;即角色是權(quán)限集合;Shiro同樣不進行權(quán)限的維護,需要我們通過Realm返回相應(yīng)的權(quán)限信息。只需要維護“用戶——角色”之間的關(guān)系即可。

 

2、測試用例(com.github.zhangkaitao.shiro.chapter3.PermissionTest)     

Java代碼  收藏代碼
  1. @Test  
  2. public void testIsPermitted() {  
  3.     login("classpath:shiro-permission.ini""zhang""123");  
  4.     //判斷擁有權(quán)限:user:create  
  5.     Assert.assertTrue(subject().isPermitted("user:create"));  
  6.     //判斷擁有權(quán)限:user:update and user:delete  
  7.     Assert.assertTrue(subject().isPermittedAll("user:update""user:delete"));  
  8.     //判斷沒有權(quán)限:user:view  
  9.     Assert.assertFalse(subject().isPermitted("user:view"));  
  10. }   

Shiro提供了isPermitted和isPermittedAll用于判斷用戶是否擁有某個權(quán)限或所有權(quán)限,也沒有提供如isPermittedAny用于判斷擁有某一個權(quán)限的接口。

 

Java代碼  收藏代碼
  1. @Test(expected = UnauthorizedException.class)  
  2. public void testCheckPermission () {  
  3.     login("classpath:shiro-permission.ini""zhang""123");  
  4.     //斷言擁有權(quán)限:user:create  
  5.     subject().checkPermission("user:create");  
  6.     //斷言擁有權(quán)限:user:delete and user:update  
  7.     subject().checkPermissions("user:delete""user:update");  
  8.     //斷言擁有權(quán)限:user:view 失敗拋出異常  
  9.     subject().checkPermissions("user:view");  
  10. }   

但是失敗的情況下會拋出UnauthorizedException異常。

 

到此基于資源的訪問控制(顯示角色)就完成了,也可以叫基于權(quán)限的訪問控制,這種方式的一般規(guī)則是“資源標(biāo)識符:操作”,即是資源級別的粒度;這種方式的好處就是如果要修改基本都是一個資源級別的修改,不會對其他模塊代碼產(chǎn)生影響,粒度小。但是實現(xiàn)起來可能稍微復(fù)雜點,需要維護“用戶——角色,角色——權(quán)限(資源:操作)”之間的關(guān)系。  

 

3.3 Permission

字符串通配符權(quán)限

規(guī)則:“資源標(biāo)識符:操作:對象實例ID”  即對哪個資源的哪個實例可以進行什么操作。其默認支持通配符權(quán)限字符串,“:”表示資源/操作/實例的分割;“,”表示操作的分割;“*”表示任意資源/操作/實例。

  

1、單個資源單個權(quán)限 

Java代碼  收藏代碼
  1. subject().checkPermissions("system:user:update");  

用戶擁有資源“system:user”的“update”權(quán)限。

 

2、單個資源多個權(quán)限

ini配置文件 

Java代碼  收藏代碼
  1. role41=system:user:update,system:user:delete  

然后通過如下代碼判斷

Java代碼  收藏代碼
  1. subject().checkPermissions("system:user:update""system:user:delete");  

用戶擁有資源“system:user”的“update”和“delete”權(quán)限。如上可以簡寫成:

 

ini配置(表示角色4擁有system:user資源的update和delete權(quán)限)   

Java代碼  收藏代碼
  1. role42="system:user:update,delete"    

 接著可以通過如下代碼判斷 

Java代碼  收藏代碼
  1. subject().checkPermissions("system:user:update,delete");  

通過“system:user:update,delete”驗證"system:user:update, system:user:delete"是沒問題的,但是反過來是規(guī)則不成立。

 

3、單個資源全部權(quán)限

ini配置 

Java代碼  收藏代碼
  1. role51="system:user:create,update,delete,view"  

然后通過如下代碼判斷 

Java代碼  收藏代碼
  1. subject().checkPermissions("system:user:create,delete,update:view");  

用戶擁有資源“system:user”的“create”、“update”、“delete”和“view”所有權(quán)限。如上可以簡寫成:

 

ini配置文件(表示角色5擁有system:user的所有權(quán)限)

Java代碼  收藏代碼
  1. role52=system:user:*  

也可以簡寫為(推薦上邊的寫法):

Java代碼  收藏代碼
  1. role53=system:user  

然后通過如下代碼判斷

Java代碼  收藏代碼
  1. subject().checkPermissions("system:user:*");  
  2. subject().checkPermissions("system:user");   

通過“system:user:*”驗證“system:user:create,delete,update:view”可以,但是反過來是不成立的。

 

4、所有資源全部權(quán)限

ini配置 

Java代碼  收藏代碼
  1. role61=*:view  

然后通過如下代碼判斷

Java代碼  收藏代碼
  1. subject().checkPermissions("user:view");  

用戶擁有所有資源的“view”所有權(quán)限。假設(shè)判斷的權(quán)限是“"system:user:view”,那么需要“role5=*:*:view”這樣寫才行。

 

5、實例級別的權(quán)限

5.1、單個實例單個權(quán)限

ini配置

Java代碼  收藏代碼
  1. role71=user:view:1  

對資源user的1實例擁有view權(quán)限。

然后通過如下代碼判斷 

Java代碼  收藏代碼
  1. subject().checkPermissions("user:view:1");  

 

5.2、單個實例多個權(quán)限

ini配置           

Java代碼  收藏代碼
  1. role72="user:update,delete:1"  

對資源user的1實例擁有update、delete權(quán)限。

然后通過如下代碼判斷

Java代碼  收藏代碼
  1. subject().checkPermissions("user:delete,update:1");  
  2. subject().checkPermissions("user:update:1""user:delete:1");   

  

5.3、單個實例所有權(quán)限

ini配置  

Java代碼  收藏代碼
  1. role73=user:*:1  

對資源user的1實例擁有所有權(quán)限。

然后通過如下代碼判斷 

Java代碼  收藏代碼
  1. subject().checkPermissions("user:update:1""user:delete:1""user:view:1");  

   

5.4、所有實例單個權(quán)限

ini配置 

Java代碼  收藏代碼
  1. role74=user:auth:*  

對資源user的1實例擁有所有權(quán)限。

然后通過如下代碼判斷 

Java代碼  收藏代碼
  1. subject().checkPermissions("user:auth:1""user:auth:2");  

  

5.5、所有實例所有權(quán)限

ini配置 

Java代碼  收藏代碼
  1. role75=user:*:*  

對資源user的1實例擁有所有權(quán)限。

然后通過如下代碼判斷     

Java代碼  收藏代碼
  1. subject().checkPermissions("user:view:1""user:auth:2");  

  

6、Shiro對權(quán)限字符串缺失部分的處理

如“user:view”等價于“user:view:*”;而“organization”等價于“organization:*”或者“organization:*:*”??梢赃@么理解,這種方式實現(xiàn)了前綴匹配。

另外如“user:*”可以匹配如“user:delete”、“user:delete”可以匹配如“user:delete:1”、“user:*:1”可以匹配如“user:view:1”、“user”可以匹配“user:view”或“user:view:1”等。即*可以匹配所有,不加*可以進行前綴匹配;但是如“*:view”不能匹配“system:user:view”,需要使用“*:*:view”,即后綴匹配必須指定前綴(多個冒號就需要多個*來匹配)。

 

7、WildcardPermission

如下兩種方式是等價的:  

Java代碼  收藏代碼
  1. subject().checkPermission("menu:view:1");  
  2. subject().checkPermission(new WildcardPermission("menu:view:1"));   

因此沒什么必要的話使用字符串更方便。

 

8、性能問題

通配符匹配方式比字符串相等匹配來說是更復(fù)雜的,因此需要花費更長時間,但是一般系統(tǒng)的權(quán)限不會太多,且可以配合緩存來提供其性能,如果這樣性能還達不到要求我們可以實現(xiàn)位操作算法實現(xiàn)性能更好的權(quán)限匹配。另外實例級別的權(quán)限驗證如果數(shù)據(jù)量太大也不建議使用,可能造成查詢權(quán)限及匹配變慢??梢钥紤]比如在sql查詢時加上權(quán)限字符串之類的方式在查詢時就完成了權(quán)限匹配。 

 

3.4 授權(quán)流程


流程如下:

1、首先調(diào)用Subject.isPermitted*/hasRole*接口,其會委托給SecurityManager,而SecurityManager接著會委托給Authorizer;

2、Authorizer是真正的授權(quán)者,如果我們調(diào)用如isPermitted(“user:view”),其首先會通過PermissionResolver把字符串轉(zhuǎn)換成相應(yīng)的Permission實例;

3、在進行授權(quán)之前,其會調(diào)用相應(yīng)的Realm獲取Subject相應(yīng)的角色/權(quán)限用于匹配傳入的角色/權(quán)限;

4、Authorizer會判斷Realm的角色/權(quán)限是否和傳入的匹配,如果有多個Realm,會委托給ModularRealmAuthorizer進行循環(huán)判斷,如果匹配如isPermitted*/hasRole*會返回true,否則返回false表示授權(quán)失敗。

 

ModularRealmAuthorizer進行多Realm匹配流程:

1、首先檢查相應(yīng)的Realm是否實現(xiàn)了實現(xiàn)了Authorizer;

2、如果實現(xiàn)了Authorizer,那么接著調(diào)用其相應(yīng)的isPermitted*/hasRole*接口進行匹配;

3、如果有一個Realm匹配那么將返回true,否則返回false。

 

如果Realm進行授權(quán)的話,應(yīng)該繼承AuthorizingRealm,其流程是:

1.1、如果調(diào)用hasRole*,則直接獲取AuthorizationInfo.getRoles()與傳入的角色比較即可;

1.2、首先如果調(diào)用如isPermitted(“user:view”),首先通過PermissionResolver將權(quán)限字符串轉(zhuǎn)換成相應(yīng)的Permission實例,默認使用WildcardPermissionResolver,即轉(zhuǎn)換為通配符的WildcardPermission;

2、通過AuthorizationInfo.getObjectPermissions()得到Permission實例集合;通過AuthorizationInfo. getStringPermissions()得到字符串集合并通過PermissionResolver解析為Permission實例;然后獲取用戶的角色,并通過RolePermissionResolver解析角色對應(yīng)的權(quán)限集合(默認沒有實現(xiàn),可以自己提供);

3、接著調(diào)用Permission. implies(Permission p)逐個與傳入的權(quán)限比較,如果有匹配的則返回true,否則false。 

 

3.5 Authorizer、PermissionResolver及RolePermissionResolver

Authorizer的職責(zé)是進行授權(quán)(訪問控制),是Shiro API中授權(quán)核心的入口點,其提供了相應(yīng)的角色/權(quán)限判斷接口,具體請參考其Javadoc。SecurityManager繼承了Authorizer接口,且提供了ModularRealmAuthorizer用于多Realm時的授權(quán)匹配。PermissionResolver用于解析權(quán)限字符串到Permission實例,而RolePermissionResolver用于根據(jù)角色解析相應(yīng)的權(quán)限集合。

 

我們可以通過如下ini配置更改Authorizer實現(xiàn): 

Java代碼  收藏代碼
  1. authorizer=org.apache.shiro.authz.ModularRealmAuthorizer  
  2. securityManager.authorizer=$authorizer   

對于ModularRealmAuthorizer,相應(yīng)的AuthorizingSecurityManager會在初始化完成后自動將相應(yīng)的realm設(shè)置進去,我們也可以通過調(diào)用其setRealms()方法進行設(shè)置。對于實現(xiàn)自己的authorizer可以參考ModularRealmAuthorizer實現(xiàn)即可,在此就不提供示例了。

 

設(shè)置ModularRealmAuthorizer的permissionResolver,其會自動設(shè)置到相應(yīng)的Realm上(其實現(xiàn)了PermissionResolverAware接口),如:

Java代碼  收藏代碼
  1. permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver  
  2. authorizer.permissionResolver=$permissionResolver   

 

設(shè)置ModularRealmAuthorizer的rolePermissionResolver,其會自動設(shè)置到相應(yīng)的Realm上(其實現(xiàn)了RolePermissionResolverAware接口),如:

Java代碼  收藏代碼
  1. rolePermissionResolver=com.github.zhangkaitao.shiro.chapter3.permission.MyRolePermissionResolver  
  2. authorizer.rolePermissionResolver=$rolePermissionResolver   

 

示例

1、ini配置(shiro-authorizer.ini    

Java代碼  收藏代碼
  1. [main]  
  2. #自定義authorizer  
  3. authorizer=org.apache.shiro.authz.ModularRealmAuthorizer  
  4. #自定義permissionResolver  
  5. #permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver  
  6. permissionResolver=com.github.zhangkaitao.shiro.chapter3.permission.BitAndWildPermissionResolver  
  7. authorizer.permissionResolver=$permissionResolver  
  8. #自定義rolePermissionResolver  
  9. rolePermissionResolver=com.github.zhangkaitao.shiro.chapter3.permission.MyRolePermissionResolver  
  10. authorizer.rolePermissionResolver=$rolePermissionResolver  
  11.   
  12. securityManager.authorizer=$authorizer  
Java代碼  收藏代碼
  1. #自定義realm 一定要放在securityManager.authorizer賦值之后(因為調(diào)用setRealms會將realms設(shè)置給authorizer,并給各個Realm設(shè)置permissionResolver和rolePermissionResolver)  
  2. realm=com.github.zhangkaitao.shiro.chapter3.realm.MyRealm  
  3. securityManager.realms=$realm   

設(shè)置securityManager 的realms一定要放到最后,因為在調(diào)用SecurityManager.setRealms時會將realms設(shè)置給authorizer,并為各個Realm設(shè)置permissionResolver和rolePermissionResolver。另外,不能使用IniSecurityManagerFactory創(chuàng)建的IniRealm,因為其初始化順序的問題可能造成后續(xù)的初始化Permission造成影響。

 

2、定義BitAndWildPermissionResolver及BitPermission

BitPermission用于實現(xiàn)位移方式的權(quán)限,如規(guī)則是:

權(quán)限字符串格式:+資源字符串+權(quán)限位+實例ID;以+開頭中間通過+分割;權(quán)限:0 表示所有權(quán)限;1 新增(二進制:0001)、2 修改(二進制:0010)、4 刪除(二進制:0100)、8 查看(二進制:1000);如 +user+10 表示對資源user擁有修改/查看權(quán)限。

Java代碼  收藏代碼
  1. public class BitPermission implements Permission {  
  2.     private String resourceIdentify;  
  3.     private int permissionBit;  
  4.     private String instanceId;  
  5.     public BitPermission(String permissionString) {  
  6.         String[] array = permissionString.split("\\+");  
  7.         if(array.length > 1) {  
  8.             resourceIdentify = array[1];  
  9.         }  
  10.         if(StringUtils.isEmpty(resourceIdentify)) {  
  11.             resourceIdentify = "*";  
  12.         }  
  13.         if(array.length > 2) {  
  14.             permissionBit = Integer.valueOf(array[2]);  
  15.         }  
  16.         if(array.length > 3) {  
  17.             instanceId = array[3];  
  18.         }  
  19.         if(StringUtils.isEmpty(instanceId)) {  
  20.             instanceId = "*";  
  21.         }  
  22.     }  
  23.   
  24.     @Override  
  25.     public boolean implies(Permission p) {  
  26.         if(!(p instanceof BitPermission)) {  
  27.             return false;  
  28.         }  
  29.         BitPermission other = (BitPermission) p;  
  30.         if(!("*".equals(this.resourceIdentify) || this.resourceIdentify.equals(other.resourceIdentify))) {  
  31.             return false;  
  32.         }  
  33.         if(!(this.permissionBit ==0 || (this.permissionBit & other.permissionBit) != 0)) {  
  34.             return false;  
  35.         }  
  36.         if(!("*".equals(this.instanceId) || this.instanceId.equals(other.instanceId))) {  
  37.             return false;  
  38.         }  
  39.         return true;  
  40.     }  
  41. }   

Permission接口提供了boolean implies(Permission p)方法用于判斷權(quán)限匹配的;

Java代碼  收藏代碼
  1. public class BitAndWildPermissionResolver implements PermissionResolver {  
  2.     @Override  
  3.     public Permission resolvePermission(String permissionString) {  
  4.         if(permissionString.startsWith("+")) {  
  5.             return new BitPermission(permissionString);  
  6.         }  
  7.         return new WildcardPermission(permissionString);  
  8.     }  
  9. }   

BitAndWildPermissionResolver實現(xiàn)了PermissionResolver接口,并根據(jù)權(quán)限字符串是否以“+”開頭來解析權(quán)限字符串為BitPermission或WildcardPermission。

 

3、定義MyRolePermissionResolver

RolePermissionResolver用于根據(jù)角色字符串來解析得到權(quán)限集合。

Java代碼  收藏代碼
  1. public class MyRolePermissionResolver implements RolePermissionResolver {  
  2.     @Override  
  3.     public Collection<Permission> resolvePermissionsInRole(String roleString) {  
  4.         if("role1".equals(roleString)) {  
  5.             return Arrays.asList((Permission)new WildcardPermission("menu:*"));  
  6.         }  
  7.         return null;  
  8.     }  
  9. }   

此處的實現(xiàn)很簡單,如果用戶擁有role1,那么就返回一個“menu:*”的權(quán)限。

 

4、自定義Realm

Java代碼  收藏代碼
  1. public class MyRealm extends AuthorizingRealm {  
  2.     @Override  
  3.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
  4.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
  5.         authorizationInfo.addRole("role1");  
  6.         authorizationInfo.addRole("role2");  
  7.         authorizationInfo.addObjectPermission(new BitPermission("+user1+10"));  
  8.         authorizationInfo.addObjectPermission(new WildcardPermission("user1:*"));  
  9.         authorizationInfo.addStringPermission("+user2+10");  
  10.         authorizationInfo.addStringPermission("user2:*");  
  11.         return authorizationInfo;  
  12.     }  
  13.     @Override  
  14.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
  15.         //和com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1. getAuthenticationInfo代碼一樣,省略  
  16. }  
  17. }   

此時我們繼承AuthorizingRealm而不是實現(xiàn)Realm接口;推薦使用AuthorizingRealm,因為:

AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token):表示獲取身份驗證信息;

AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals):表示根據(jù)用戶身份獲取授權(quán)信息。

這種方式的好處是當(dāng)只需要身份驗證時只需要獲取身份驗證信息而不需要獲取授權(quán)信息。對于AuthenticationInfo和AuthorizationInfo請參考其Javadoc獲取相關(guān)接口信息。

 

另外我們可以使用JdbcRealm,需要做的操作如下:

1、執(zhí)行sql/ shiro-init-data.sql 插入相關(guān)的權(quán)限數(shù)據(jù);

2、使用shiro-jdbc-authorizer.ini配置文件,需要設(shè)置jdbcRealm.permissionsLookupEnabled

為true來開啟權(quán)限查詢。

 

此次還要注意就是不能把我們自定義的如“+user1+10”配置到INI配置文件,即使有IniRealm完成,因為IniRealm在new完成后就會解析這些權(quán)限字符串,默認使用了WildcardPermissionResolver完成,即此處是一個設(shè)計權(quán)限,如果采用生命周期(如使用初始化方法)的方式進行加載就可以解決我們自定義permissionResolver的問題。

 

5、測試用例

Java代碼  收藏代碼
  1. public class AuthorizerTest extends BaseTest {  
  2.   
  3.     @Test  
  4.     public void testIsPermitted() {  
  5.         login("classpath:shiro-authorizer.ini""zhang""123");  
  6.         //判斷擁有權(quán)限:user:create  
  7.         Assert.assertTrue(subject().isPermitted("user1:update"));  
  8.         Assert.assertTrue(subject().isPermitted("user2:update"));  
  9.         //通過二進制位的方式表示權(quán)限  
  10.         Assert.assertTrue(subject().isPermitted("+user1+2"));//新增權(quán)限  
  11.         Assert.assertTrue(subject().isPermitted("+user1+8"));//查看權(quán)限  
  12.         Assert.assertTrue(subject().isPermitted("+user2+10"));//新增及查看  
  13.   
  14.         Assert.assertFalse(subject().isPermitted("+user1+4"));//沒有刪除權(quán)限  
  15.   
  16.         Assert.assertTrue(subject().isPermitted("menu:view"));//通過MyRolePermissionResolver解析得到的權(quán)限  
  17.     }  
  18. }   

通過如上步驟可以實現(xiàn)自定義權(quán)限驗證了。另外因為不支持hasAnyRole/isPermittedAny這種方式的授權(quán),可以參考我的一篇《簡單shiro擴展實現(xiàn)NOT、AND、OR權(quán)限驗證 》進行簡單的擴展完成這個需求,在這篇文章中通過重寫AuthorizingRealm里的驗證邏輯實現(xiàn)的。       

 

示例源代碼:https://github.com/zhangkaitao/shiro-example;可加群134755960探討Spring/Shiro技術(shù)。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多