shiro中基於注解實現的權限認證過程


授權即訪問控制,它將判斷用戶在應用程序中對資源是否擁有相應的訪問權限。 

如,判斷一個用戶有查看頁面的權限,編輯數據的權限,擁有某一按鈕的權限等等。 

 

一、用戶權限模型

為實現一個較為靈活的用戶權限數據模型,通常把用戶信息單獨用一個實體表示,用戶權限信息用兩個實體表示。

  1. 用戶信息用 LoginAccount 表示,最簡單的用戶信息可能只包含用戶名 loginName 及密碼 password 兩個屬性。實際應用中可能會包含用戶是否被禁用,用戶信息是否過期等信息。
  2. 用戶權限信息用 Role 與 Permission 表示,Role 與 Permission 之間構成多對多關系。Permission 可以理解為對一個資源的操作,Role 可以簡單理解為 Permission 的集合。
  3. 用戶信息與 Role 之間構成多對多關系。表示同一個用戶可以擁有多個 Role,一個 Role 可以被多個用戶所擁有。

 

 

權限聲明及粒度 

Shiro權限聲明通常是使用以冒號分隔的表達式。就像前文所講,一個權限表達式可以清晰的指定資源類型,允許的操作。同時,Shiro權限表達式支持簡單的通配符,可以更加靈活的進行權限設置。 

下面以實例來說明權限表達式。 

可查詢用戶數據 

User:view 

可查詢或編輯用戶數據 

User:view,edit 

可對用戶數據進行所有操作 

User:*或 user 

可編輯id為123的用戶數據 

User:edit:123 

 

授權處理過程

認證通過后接受 Shiro 授權檢查,授權驗證時,需要判斷當前角色是否擁有該權限。

只有授權通過,才可以訪問受保護 URL 對應的資源,否則跳轉到“未經授權頁面”。

如果我們自定義Realm實現,比如我后面的例子中,自定義了ShiroDbRealm類,當訪問被@RequiresPermissions注解的方法時,會先執行ShiroDbRealm.doGetAuthorizationInfo()進行授權。

 

[java]  view plain  copy
 
  1. <span style="font-size:18px">@Controller  
  2. @RequestMapping(value = "/user")  
  3. public class UserController {  
  4.    
  5. @Resource(name="userService")  
  6. private IUserService userService;  
  7.    
  8. /** 
  9.  * 測試權限 
  10.  * 只有擁有 user:create權限,才能進行注冊 
  11.  * @param user 
  12.  * @return 
  13.  */  
  14. @RequestMapping(value = "/register")  
  15. @ResponseBody  
  16. @RequiresPermissions("user:create")  
  17. public boolean register(User user){  
  18. return userService.register(user);  
  19. }</span>  



 

 

 

二、授權實現 

Shiro支持三種方式實現授權過程: 

  • 編碼實現
  • 注解實現
  • JSP Taglig實現

 

1、基於編碼的授權實現 

1、基於權限對象的實現 

創建org.apache.shiro.authz.Permission的實例,將該實例對象作為參數傳遞給Subject.isPermitted()進行驗證。 

      

[java]  view plain  copy
 
  1. Permission printPermission = new PrinterPermission("laserjet4400n", "print");    
  2. Subject currentUser = SecurityUtils.getSubject();    
  3. if (currentUser.isPermitted(printPermission)) {    
  4.     //show the Print button    
  5. else {    
  6.     //don't show the button?  Grey it out?    
  7. }    

 

 

 

2基於字符串的實現 

相比笨重的基於對象的實現方式,基於字符串的實現便顯得更加簡潔。 

       

[java]  view plain  copy
 
  1. Subject currentUser = SecurityUtils.getSubject();    
  2. if (currentUser.isPermitted("printer:print:laserjet4400n")) {    
  3.     //show the Print button    
  4. else {    
  5.     //don't show the button?  Grey it out?    
  6. }    

 

 

使用冒號分隔的權限表達式是org.apache.shiro.authz.permission.WildcardPermission默認支持的實現方式。 

這里分別代表了資源類型:操作:資源ID 

 

2、基於注解的授權實現 

Shiro注解支持AspectJ、Spring、Google-Guice等,可根據應用進行不同的配置。 

 

相關的注解: 

@RequiresAuthentication 

可以用戶類/屬性/方法,用於表明當前用戶需是經過認證的用戶。  

        

[java]  view plain  copy
 
  1. @RequiresAuthentication    
  2. public void updateAccount(Account userAccount) {    
  3.     //this method will only be invoked by a     
  4.     //Subject that is guaranteed authenticated    
  5.     ...    
  6. }   

 

 

@RequiresPermissions 

當前用戶需擁有制定權限 

       

[java]  view plain  copy
 
  1. @RequiresPermissions("account:create")    
  2. public void createAccount(Account account) {    
  3.     //this method will only be invoked by a Subject    
  4.     //that is permitted to create an account    
  5.     ...    
  6. }   


 

 

 

3、基於JSP TAG的授權實現 

Shiro提供了一套JSP標簽庫來實現頁面級的授權控制。 

在使用Shiro標簽庫前,首先需要在JSP引入shiro標簽: 

 

[html]  view plain  copy
 
  1. <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>  

 

 

hasRole標簽 

驗證當前用戶是否屬於該角色

 

[html]  view plain  copy
 
  1. <shiro:hasRole name="administrator">    
  2.     <href="admin.jsp">Administer the system</a>    
  3. </shiro:hasRole>    

 

 

hasPermission標簽 

驗證當前用戶是否擁有制定權限 

 

[html]  view plain  copy
 
  1. <shiro:hasPermission name="user:create">    
  2.     <href="createUser.jsp">Create a new User</a>    
  3. </shiro:hasPermission>    



 

 

三、Shiro授權的內部處理機制 

 

1、在應用程序中調用授權驗證方法(Subject的isPermitted*或hasRole*等) 

2、Sbuject會委托應用程序設置的securityManager實例調用相應的isPermitted*或hasRole*方法。 

3、接下來SecurityManager會委托內置的Authorizer的實例(默認是ModularRealmAuthorizer類的實例,類似認證實例)調用相應的授權方法。 

4、每一個Realm將檢查是否實現了相同的Authorizer 接口。然后,將調用Reaml自己的相應的授權驗證方法。 

 

四、授權代碼

UserController:處理用戶登錄后的請求(注冊)

    

[java]  view plain  copy
 
  1. package org.shiro.demo.controller;  
  2.   
  3. import javax.annotation.Resource;  
  4.   
  5. import org.apache.shiro.authz.annotation.RequiresPermissions;  
  6. import org.apache.shiro.authz.annotation.RequiresRoles;  
  7. import org.shiro.demo.entity.User;  
  8. import org.shiro.demo.service.IUserService;  
  9. import org.springframework.stereotype.Controller;  
  10. import org.springframework.web.bind.annotation.RequestMapping;  
  11. import org.springframework.web.bind.annotation.ResponseBody;  
  12.   
  13. @Controller  
  14. @RequestMapping(value = "/user")  
  15. public class UserController {  
  16.       
  17.     @Resource(name="userService")  
  18.     private IUserService userService;  
  19.   
  20.     /** 
  21.      * 測試權限 
  22.      * 只有擁有 user:create 權限,才能進行注冊 
  23.      * @param user 
  24.      * @return 
  25.      */  
  26.     @RequestMapping(value = "/register")  
  27.     @ResponseBody  
  28.     @RequiresPermissions("user:create")  
  29.     public boolean register(User user){  
  30.         return userService.register(user);  
  31.     }  
  32.       
  33.     /** 
  34.      * 測試角色 
  35.      * 只有擁有 administrator 角色,才能跳轉到register頁面 
  36.      * @return 
  37.      */  
  38.     @RequestMapping(value = "/toRegister")  
  39.     @RequiresRoles("administrator")  
  40.     public String toRegister(){  
  41.         return "/system/user/register";  
  42.     }  
  43. }  

 

 

 

ShiroDbRealm:自定義的指定Shiro驗證用戶授權的類

 

[java]  view plain  copy
 
    1. <span style="font-size:18px">packageorg.shiro.demo.service.realm;  
    2.    
    3. importjava.util.ArrayList;  
    4. importjava.util.List;  
    5.    
    6. importjavax.annotation.Resource;  
    7.    
    8. importorg.apache.commons.lang.StringUtils;  
    9. importorg.apache.shiro.authc.AuthenticationException;  
    10. importorg.apache.shiro.authc.AuthenticationInfo;  
    11. importorg.apache.shiro.authc.AuthenticationToken;  
    12. importorg.apache.shiro.authc.SimpleAuthenticationInfo;  
    13. importorg.apache.shiro.authc.UsernamePasswordToken;  
    14. importorg.apache.shiro.authz.AuthorizationException;  
    15. importorg.apache.shiro.authz.AuthorizationInfo;  
    16. importorg.apache.shiro.authz.SimpleAuthorizationInfo;  
    17. importorg.apache.shiro.realm.AuthorizingRealm;  
    18. importorg.apache.shiro.subject.PrincipalCollection;  
    19. importorg.shiro.demo.entity.Permission;  
    20. importorg.shiro.demo.entity.Role;  
    21. importorg.shiro.demo.entity.User;  
    22. importorg.shiro.demo.service.IUserService;  
    23.    
    24. /** 
    25.  * 自定義的指定Shiro驗證用戶登錄的類 
    26.  * @author TCH 
    27.  * 
    28.  */  
    29. publicclass ShiroDbRealm extends AuthorizingRealm{  
    30.    
    31. //@Resource(name="userService")  
    32. privateIUserService userService;  
    33.    
    34. publicvoid setUserService(IUserService userService) {  
    35. this.userService= userService;  
    36. }  
    37.    
    38.     /** 
    39.      * 為當前登錄的Subject授予角色和權限 
    40.      * @see 經測試:本例中該方法的調用時機為需授權資源被訪問時 
    41.      * @see經測試:並且每次訪問需授權資源時都會執行該方法中的邏輯,這表明本例未啟用AuthorizationCache 
    42.      * @seeweb層可以有shiro的緩存,dao層可以配有hibernate的緩存(后面介紹) 
    43.      */  
    44. protectedAuthorizationInfo doGetAuthorizationInfo(  
    45. PrincipalCollectionprincipals) {  
    46.    
    47. //獲取當前登錄的用戶名,等價於(String)principals.fromRealm(this.getName()).iterator().next()   
    48. Stringaccount = (String) super.getAvailablePrincipal(principals);  
    49.    
    50. List<String>roles = new ArrayList<String>();   
    51. List<String>permissions = new ArrayList<String>();  
    52.    
    53. //從數據庫中獲取當前登錄用戶的詳細信息   
    54. Useruser = userService.getByAccount(account);  
    55.    
    56. if(user!= null){  
    57. //實體類User中包含有用戶角色的實體類信息   
    58. if(user.getRoles() != null && user.getRoles().size() > 0) {  
    59. //獲取當前登錄用戶的角色  
    60. for(Role role : user.getRoles()) {  
    61. roles.add(role.getName());  
    62.  //實體類Role中包含有角色權限的實體類信息   
    63. if(role.getPmss() != null && role.getPmss().size() > 0) {  
    64.  //獲取權限   
    65. for(Permission pmss : role.getPmss()) {  
    66. if(!StringUtils.isEmpty(pmss.getPermission())){  
    67. permissions.add(pmss.getPermission());  
    68. }  
    69. }  
    70. }  
    71. }  
    72. }  
    73. }else{  
    74. thrownew AuthorizationException();  
    75. }  
    76.    
    77. //為當前用戶設置角色和權限  
    78. SimpleAuthorizationInfoinfo = new SimpleAuthorizationInfo();  
    79. info.addRoles(roles);  
    80.         info.addStringPermissions(permissions);  
    81.          
    82. returninfo;  
    83.    
    84. }  
    85.    
    86. }</span>  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM