【Shiro】Apache Shiro架構之權限認證(Authorization)

上一篇博文總結了一下Shiro中的身份認證,本文主要來總結一下Shiro中的權限認證(Authorization)功能,即授權。如下: 
授權 
  本文參考自Apache Shiro的官方文檔:http://shiro.apache.org/authorization.html。 
  本文遵循以下流程:先介紹Shiro中的權限認證,再通過一個簡單的實例來具體說明一下API的使用(基於maven)。

1. 權限認證的核心要素

  權限認證,也就是訪問控制,即在應用中控制誰能訪問哪些資源。在權限認證中,最核心的三個要素是:權限,角色和用戶:

權限(permission):即操作資源的權利,比如訪問某個頁面,以及對某個模塊的數據的添加,修改,刪除,查看的權利; 
角色(role):指的是用戶擔任的的角色,一個角色可以有多個權限; 
用戶(user):在Shiro 中,代表訪問系統的用戶,即上一篇博文提到的Subject認證主體。

  它們之間的的關係可以用下圖來表示: 
關係
  一個用戶可以有多個角色,而不同的角色可以有不同的權限,也可由有相同的權限。比如說現在有三個角色,1是普通角色,2也是普通角色,3是管理員,角色1只能查看信息,角色2只能添加信息,管理員都可以,而且還可以刪除信息,類似於這樣。

2.1 基於角色的訪問控制

  也就是說,授權過程是通過判斷角色來完成的,哪個角色可以做這件事,哪些角色可以做這件事等等。它有如下API:

方法作用
hasRole(String roleName)判斷是否有該角色訪問權,返回boolen
hasRoles(List<String> roleNames)判斷是否有這些這些角色訪問權,返回boolean[]
hasAllRoles(Collection<String> roleNames)判斷是否有這些這些角色訪問權,返回boolean

  對這三個API,做一下簡單的說明,第一個很簡單,傳入一個role即可,判斷是否擁有該角色訪問權,第二個方法是傳入一個role的集合,然後Shiro會根據集合中的每一個role做一下判斷,並且將每次的判斷結果放到boolean[]數組中,順序與集合中role的順序一致;第三個方法也是傳入一個role的集合,不同的是,返回boolean類型,必須集合中全部role都有才爲true,否則爲false。 
  用法如下:

Subject currentUser = SecurityUtils.getSubject();
if (currentUser.hasRole("administrator")) {
    //show the admin button or do administrator's things
} else {
    //don't show the button?  Grey it out? or others...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  除了這三個API外,Shiro還提供了check的API,與上面不同的是,has-xxx會返回boolean類型的數據,用來判斷,而check-xxx不會返回任何東西,如果驗證成功就繼續處理下面的代碼,否則會拋出一個異常,可以用來通過捕獲異常來處理。API如下:

方法作用
checkRole(String roleName)如果判斷失敗拋出AuthorizationException異常
checkRoles(String... roleNames)如果判斷失敗拋出AuthorizationException異常
checkRoles(Collection<String> roleNames)如果判斷失敗拋出AuthorizationException異常

  類似的使用方法如下:

Subject currentUser = SecurityUtils.getSubject();
//guarantee that the current user is a bank teller and
//therefore allowed to open the account:
currentUser.checkRole("bankTeller");
openBankAccount();
  • 1
  • 2
  • 3
  • 4
  • 5

2.2 基於權限的訪問控制

  基於權限的訪問控制和基於角色的訪問控制在原理上是一模一樣的,只不過API不同而已,我不再做過多的解釋,API如下:

方法作用
isPermitted(String perm)判斷是否有該權限,返回boolen
isPermitted(List<String> perms)判斷是否有這些這些權限,返回boolean[]
isPermittedAll(Collection<String> perms)判斷是否有這些這些權限,返回boolean
checkPermission(String perm)如果判斷失敗拋出AuthorizationException異常
checkPermissions(String... perms)如果判斷失敗拋出AuthorizationException異常
checkPermissionsAll(Collection<String> perms)如果判斷失敗拋出AuthorizationException異常

3. 權限認證示例代碼

  不管是身份認證還是權限認證,首先都需要創建SecurityManager工廠,SecurityManager,所以首先新建一個工具類專門做這個事情。

public class ShiroUtil {

    public static Subject login(String configFile, String username,
            String password) {

        // 讀取配置文件,初始化SecurityManager工廠
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
        // 獲取securityManager實例
        SecurityManager securityManager = factory.getInstance();
        // 把securityManager實例綁定到SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);
        // 得到當前執行的用戶
        Subject currentUser = SecurityUtils.getSubject();
        // 創建token令牌,用戶名/密碼
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try{
            // 身份認證
            currentUser.login(token);   
            System.out.println("身份認證成功!");
        }catch(AuthenticationException e){
            e.printStackTrace();
            System.out.println("身份認證失敗!");
        }
        return currentUser;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

  提供一個靜態方法,返回當前用戶,在應用程序中我們直接調用這個類中的靜態方法即可返回當前認證的用戶了。 
  maven中的pom.xml文件內容和上一節一樣的,不再贅述。 
  Shiro的配置文件shiro.ini:

#用戶,role表示各個角色
[users]
csdn1=123,role1,role2,role3
csdn2=123,role1,role2

#定義不同角色都擁有哪些權限
[roles]
role1=user:select
role2=user:add,user:update
role3=user.delete
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

角色認證:

public class RoleTest {

    @Test
    public void testHasRole() {

        String configFile = "classpath:shiro.ini";
        String username = "csdn2";
        String password = "123";
        Subject currentUser = ShiroUtil.login(configFile, username, password);

        //測試hasRole
        System.out.println(currentUser.hasRole("role2")? "有role2這個角色" : "沒有role2這個角色");

        //測試hasRoles
        boolean[] results = currentUser.hasRoles(Arrays.asList("role1","role2","role3"));
        System.out.println(results[0]? "有role1這個角色" : "沒有role1這個角色");
        System.out.println(results[1]? "有role2這個角色" : "沒有role2這個角色");
        System.out.println(results[2]? "有role3這個角色" : "沒有role3這個角色");

        //測試hasAllRoles     System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2","role3")));

        currentUser.logout();
    }

    @Test
    public void testCheckRole() {

        String configFile = "classpath:shiro.ini";
        String username = "csdn2";
        String password = "123";
        Subject currentUser = ShiroUtil.login(configFile, username, password);

//      currentUser.checkRole("role3");//沒有返回值。有就不報錯,沒有就會報錯
//      currentUser.checkRoles(Arrays.asList("role1","role2","role3")); //同上
        currentUser.checkRoles(Arrays.asList("role1","role2")); //同上

        currentUser.logout();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

  權限認證和角色認證的測試一樣的,我就不再贅述了。當然了,這裏只是單純的測試,實際中,認證完了後還要做一些具體的業務邏輯處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章