天天看點

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

歡迎關注我新搭建的部落格:http://www.itcodai.com/

Shiro系列文章:

【Shiro】Apache Shiro架構之身份認證(Authentication)

【Shiro】Apache Shiro架構之內建web

【Shiro】Apache Shiro架構之自定義realm

【Shiro】Apache Shiro架構之實際運用(整合到Spring中)

  

  上一篇博文總結了一下Shiro中的身份認證,本文主要來總結一下Shiro中的權限認證(Authorization)功能,即授權。如下:

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

  本文參考自Apache Shiro的官方文檔:http://shiro.apache.org/authorization.html。

  本文遵循以下流程:先介紹Shiro中的權限認證,再通過一個簡單的執行個體來具體說明一下API的使用(基于maven)。

1. 權限認證的核心要素

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

權限(permission):即操作資源的權利,比如通路某個頁面,以及對某個子產品的資料的添加,修改,删除,檢視的權利;

角色(role):指的是使用者擔任的的角色,一個角色可以有多個權限;

使用者(user):在Shiro 中,代表通路系統的使用者,即上一篇博文提到的Subject認證主體。

  它們之間的的關系可以用下圖來表示:

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

  一個使用者可以有多個角色,而不同的角色可以有不同的權限,也可由有相同的權限。比如說現在有三個角色,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...
}
           

  除了這三個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();
           

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;
    }
}
           

  提供一個靜态方法,傳回目前使用者,在應用程式中我們直接調用這個類中的靜态方法即可傳回目前認證的使用者了。

  maven中的pom.xml檔案内容和上一節一樣的,不再贅述。

  Shiro的配置檔案shiro.ini:

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

#定義不同角色都擁有哪些權限
[roles]
role1=user:select
role2=user:add,user:update
role3=user.delete
           

角色認證:

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[]? "有role1這個角色" : "沒有role1這個角色");
        System.out.println(results[]? "有role2這個角色" : "沒有role2這個角色");
        System.out.println(results[]? "有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();
    }
}
           

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

文末福利:“程式員私房菜”,一個有溫度的公衆号~

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

—–樂于分享,共同進步!

—–我的部落格首頁:http://blog.csdn.net/eson_15