shiro權(quán)限控制學(xué)習(xí)---授權(quán)

角色

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

隱式角色:

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

顯示角色:

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



授權(quán)

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

  1. 在ini配置文件配置用戶擁有的角色

shiro-role.ini

[users]  
admin=123,role1,role2  
root=123,role1   

規(guī)則即:“用戶名=密碼,角色1,角色2”,如果需要在應(yīng)用中判斷用戶是否有相應(yīng)角色,就需要在相應(yīng)的Realm中返回角色信息,也就是說Shiro不負(fù)責(zé)維護(hù)用戶-角色信息,需要應(yīng)用提供,Shiro只是提供相應(yīng)的接口方便驗(yàn)證

  1. 測試
  • 我們可以將身份驗(yàn)證的代碼抽出來,方便后續(xù)驗(yàn)證
    BaseTest.java
public abstract class BaseTest {

    @After
    public void tearDown() throws Exception{
        ThreadContext.unbindSubject();  //退出時(shí)請(qǐng)解除綁定Subject到線程,否則對(duì)下次測試造成影響
    }

    protected void login(String configFile, String username, String password) {
        //1.獲取SecurityManager工廠,此處使用ini配置文件初始化SecurityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);

        //2.得到SecurityManager實(shí)例,并綁定給SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        //3.得到Subject及創(chuàng)建用戶名/密碼身份驗(yàn)證token
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        subject.login(token);
    }

    public Subject subject() {
        return SecurityUtils.getSubject();
    }
}
  • 測試代碼
    @Test
    public void testHasRole() {
        login("classpath:shiro-role.ini", "admin", "123");

        //判斷擁有角色:role1
        Assert.assertTrue(subject().hasRole("role1"));
        //判斷擁有角色:role1,role2
        Assert.assertTrue(subject().hasAllRoles(Arrays.asList("role1", "role2")));
        //判斷擁有角色:role1 and role2 and !role3`
        boolean[] result = subject().hasRoles(Arrays.asList("role1", "role2", "role3"));
        System.out.println(result[0]);
        System.out.println(result[1]);
        System.out.println(result[2]);
        Assert.assertEquals(true, result[0]);
        Assert.assertEquals(true, result[1]);
        Assert.assertEquals(false, result[2]);
    }
測試結(jié)果

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

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

@Test(expected = UnauthorizedException.class)  
public void testCheckRole() {  
    login("classpath:shiro-role.ini", "admin", "123");  
    //斷言擁有角色:role1  
    subject().checkRole("role1");  
    //斷言擁有角色:role1 and role3 失敗拋出異常  
    subject().checkRoles("role1", "role3");  
} 

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

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

[users]
admin=123,role1,role2
root=123,role1
[roles]
role1=user:create,user:update
role2=user:create,user:delete

規(guī)則:“用戶名=密碼,角色1,角色2” “角色=權(quán)限1,權(quán)限2”
2、測試代碼

@Test  
public void testIsPermitted() {  
    login("classpath:shiro-permission.ini", "admin", "123");  
    //判斷擁有權(quán)限:user:create  
    Assert.assertTrue(subject().isPermitted("user:create"));  
    //判斷擁有權(quán)限:user:update and user:delete  
    Assert.assertTrue(subject().isPermittedAll("user:update", "user:delete"));  
    //判斷沒有權(quán)限:user:view  
    Assert.assertFalse(subject().isPermitted("user:view"));  
}  

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



授權(quán)流程


流程如下:

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

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

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

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

ModularRealmAuthorizer進(jìn)行多Realm匹配流程:

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

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

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

如果Realm進(jìn)行授權(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實(shí)例,默認(rèn)使用WildcardPermissionResolver,即轉(zhuǎn)換為通配符的WildcardPermission;

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

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

Authorizer、PermissionResolver及RolePermissionResolver

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 學(xué)習(xí)任務(wù)目標(biāo) 用戶必須要登陸之后才能訪問定義鏈接,否則跳轉(zhuǎn)到登錄頁面。 對(duì)鏈接進(jìn)行權(quán)限控制,只有當(dāng)當(dāng)前登錄用戶有這...
    z77z閱讀 71,436評(píng)論 39 274
  • 一、架構(gòu) 要學(xué)習(xí)如何使用Shiro必須先從它的架構(gòu)談起,作為一款安全框架Shiro的設(shè)計(jì)相當(dāng)精妙。Shiro的應(yīng)用...
    ITsupuerlady閱讀 3,626評(píng)論 4 32
  • 昨晚,看到qq通知,滿懷期待的打開,卻發(fā)現(xiàn)不是我想得那個(gè)人。 今天看了好多遍手機(jī),卻只有我最后說的話和qq標(biāo)識(shí)降級(jí)...
    學(xué)長醬閱讀 164評(píng)論 0 0
  • id類型的成員屬性->協(xié)議->告訴對(duì)應(yīng)對(duì)象應(yīng)該實(shí)現(xiàn)哪些方法自己調(diào)用方法,然后由代理對(duì)象實(shí)現(xiàn)-> responds...
    ShenYj閱讀 336評(píng)論 0 2

友情鏈接更多精彩內(nèi)容