理解Shiro身份認(rèn)證授權(quán)原理

shiro安全框架的核心就是認(rèn)證和授權(quán),前面已談到關(guān)于restful的改造,本文主要談一下認(rèn)證和授權(quán)過程,以及粗粒度和細(xì)粒度的授權(quán)等。
參考:https://blog.csdn.net/johnstrive/article/details/74741783

權(quán)限管理

基本上涉及到用戶參與的系統(tǒng)都要權(quán)限管理,權(quán)限管理屬于系統(tǒng)安全的范疇,權(quán)限管理實(shí)現(xiàn)對(duì)用戶訪問系統(tǒng)的控制,按照安全規(guī)則或者安全策略控制用戶可以訪問而且只能訪問自己被授權(quán)的資源。
權(quán)限管理包括身份認(rèn)證授權(quán)兩部分,簡(jiǎn)稱認(rèn)證授權(quán)。對(duì)于需要訪問控制的資源用戶首先經(jīng)過身份認(rèn)證,認(rèn)證通過后用戶具有該資源的訪問權(quán)限方可訪問。

身份認(rèn)證

判斷一個(gè)用戶是否為合法用戶的處理過程。最常用的簡(jiǎn)單身份認(rèn)證方式是系統(tǒng)通過核對(duì)用戶輸入的用戶名和口令,看其是否與系統(tǒng)中存儲(chǔ)的該用戶的用戶名和口令一致,來判斷用戶身份是否正確。對(duì)于采用指紋等系統(tǒng),則出示指紋;對(duì)于硬件Key等刷卡系統(tǒng),則需要刷卡。

認(rèn)證關(guān)鍵對(duì)象

  • Subject:主體
    訪問系統(tǒng)的用戶,主體可以是用戶、程序等,進(jìn)行認(rèn)證的都稱為主體;
  • Principal:身份信息
    是主體(subject)進(jìn)行身份認(rèn)證的標(biāo)識(shí),標(biāo)識(shí)必須具有唯一性,如用戶名、手機(jī)號(hào)、郵箱地址等,一個(gè)主體可以有多個(gè)身份,但是必須有一個(gè)主身份(Primary Principal)。
  • credential:憑證信息
    是只有主體自己知道的安全信息,如密碼、證書等。

授權(quán)

授權(quán),即訪問控制,控制誰能訪問哪些資源。主體進(jìn)行身份認(rèn)證后需要分配權(quán)限方可訪問系統(tǒng)的資源,對(duì)于某些資源沒有權(quán)限是無法訪問的。

授權(quán)關(guān)鍵對(duì)象

授權(quán)可簡(jiǎn)單理解為 who 對(duì) what(which) 進(jìn)行 How 操作:

  • Who,即主體(Subject),主體需要訪問系統(tǒng)中的資源。
  • What,即資源(Resource),如系統(tǒng)菜單、頁面、按鈕、類方法、系統(tǒng)商品信息等。資源包括資源類型和資源實(shí)例,比如商品信息為資源類型,類型為t01的商品為資源實(shí)例,編號(hào)為001的商品信息也屬于資源實(shí)例。
  • How,權(quán)限/許可(Permission),規(guī)定了主體對(duì)資源的操作許可,權(quán)限離開資源沒有意義,如用戶查詢權(quán)限、用戶添加權(quán)限、某個(gè)類方法的調(diào)用權(quán)限、編號(hào)為001用戶的修改權(quán)限等,通過權(quán)限可知主體對(duì)哪些資源都有哪些操作許可。
    權(quán)限分為粗顆粒和細(xì)顆粒,粗顆粒權(quán)限是指對(duì)資源類型的權(quán)限,細(xì)顆粒權(quán)限是對(duì)資源實(shí)例的權(quán)限。

權(quán)限模型

對(duì)上節(jié)中的主體、資源、權(quán)限通過數(shù)據(jù)模型表示。

  • 主體(賬號(hào)、密碼)
  • 角色(角色名稱)
  • 主體和角色關(guān)系(主體id、角色id)
  • 權(quán)限(權(quán)限名稱、資源id)
  • 角色和權(quán)限關(guān)系(角色id、權(quán)限id)
  • 資源(資源id、訪問地址)

如下圖:


image.png

權(quán)限控制

基于角色的訪問控制

RBAC基于角色的訪問控制(Role-Based Access Control)是以角色為中心進(jìn)行訪問控制,比如:主體的角色為總經(jīng)理可以查詢企業(yè)運(yùn)營(yíng)報(bào)表,查詢員工工資信息等,訪問控制流程如下:

image.png

圖中的判斷邏輯代碼可以理解為:

if(主體.hasRole("總經(jīng)理角色id")){
    查詢工資
}

缺點(diǎn):以角色進(jìn)行訪問控制粒度較粗,如果上圖中查詢工資所需要的角色變化為總經(jīng)理和部門經(jīng)理,此時(shí)就需要修改判斷邏輯為“判斷主體的角色是否是總經(jīng)理或部門經(jīng)理”,系統(tǒng)可擴(kuò)展性差。
修改代碼如下:

if(主體.hasRole("總經(jīng)理角色id") ||  主體.hasRole("部門經(jīng)理角色id")){
    查詢工資
}

基于資源的訪問控制

RBAC基于資源的訪問控制(Resource-Based Access Control)是以資源為中心進(jìn)行訪問控制,比如:主體必須具有查詢工資權(quán)限才可以查詢員工工資信息等,訪問控制流程如下:

image.png

上圖中的判斷邏輯代碼可以理解為:

if(主體.hasPermission("wage:query")){
    查詢工資
}

優(yōu)點(diǎn):系統(tǒng)設(shè)計(jì)時(shí)定義好查詢工資的權(quán)限標(biāo)識(shí),即使查詢工資所需要的角色變化為總經(jīng)理和部門經(jīng)理也只需要將“查詢工資信息權(quán)限”添加到“部門經(jīng)理角色”的權(quán)限列表中,判斷邏輯不用修改,系統(tǒng)可擴(kuò)展性強(qiáng)。

粗顆粒度和細(xì)顆粒度

什么是粗顆粒度和細(xì)顆粒度

對(duì)資源類型的管理稱為粗顆粒度權(quán)限管理,即只控制到菜單、按鈕、方法,粗粒度的例子比如:用戶具有用戶管理的權(quán)限,具有導(dǎo)出訂單明細(xì)的權(quán)限。對(duì)資源實(shí)例的控制稱為細(xì)顆粒度權(quán)限管理,即控制到數(shù)據(jù)級(jí)別的權(quán)限,比如:用戶只允許修改本部門的員工信息,用戶只允許導(dǎo)出自己創(chuàng)建的訂單明細(xì)。

如何實(shí)現(xiàn)粗顆粒度和細(xì)顆粒度

對(duì)于粗顆粒度的權(quán)限管理可以很容易做系統(tǒng)架構(gòu)級(jí)別的功能,即系統(tǒng)功能操作使用統(tǒng)一的粗顆粒度的權(quán)限管理。
對(duì)于細(xì)顆粒度的權(quán)限管理不建議做成系統(tǒng)架構(gòu)級(jí)別的功能,因?yàn)閷?duì)數(shù)據(jù)級(jí)別的控制是系統(tǒng)的業(yè)務(wù)需求,隨著業(yè)務(wù)需求的變更業(yè)務(wù)功能變化的可能性很大,建議對(duì)數(shù)據(jù)級(jí)別的權(quán)限控制在業(yè)務(wù)層個(gè)性化開發(fā),比如:用戶只允許修改自己創(chuàng)建的商品信息可以在service接口添加校驗(yàn)實(shí)現(xiàn),service接口需要傳入當(dāng)前操作人的標(biāo)識(shí),與商品信息創(chuàng)建人標(biāo)識(shí)對(duì)比,不一致則不允許修改商品信息。

基于url攔截

基于url攔截是企業(yè)中常用的權(quán)限管理方法,實(shí)現(xiàn)思路是:將系統(tǒng)操作的每個(gè)url配置在權(quán)限表中,將權(quán)限對(duì)應(yīng)到角色,將角色分配給用戶,用戶訪問系統(tǒng)功能通過Filter進(jìn)行過慮,過慮器獲取到用戶訪問的url,只要訪問的url是用戶分配角色中的url則放行繼續(xù)訪問。
如下圖:

image.png

Shiro中關(guān)鍵對(duì)象

  • Subject
    即主體,外部應(yīng)用與subject進(jìn)行交互,subject記錄了當(dāng)前操作用戶,將用戶的概念理解為當(dāng)前操作的主體,可能是一個(gè)通過瀏覽器請(qǐng)求的用戶,也可能是一個(gè)運(yùn)行的程序。 Subject在shiro中是一個(gè)接口,接口中定義了很多認(rèn)證授權(quán)相關(guān)的方法,外部程序通過subject進(jìn)行認(rèn)證授,而subject是通過SecurityManager安全管理器進(jìn)行認(rèn)證授權(quán)
  • SecurityManager
    即安全管理器,對(duì)全部的subject進(jìn)行安全管理,它是shiro的核心,負(fù)責(zé)對(duì)所有的subject進(jìn)行安全管理。通過SecurityManager可以完成subject的認(rèn)證、授權(quán)等,實(shí)質(zhì)上SecurityManager是通過Authenticator進(jìn)行認(rèn)證,通過Authorizer進(jìn)行授權(quán),通過SessionManager進(jìn)行會(huì)話管理等。
    SecurityManager是一個(gè)接口,繼承了Authenticator, Authorizer, SessionManager這三個(gè)接口。
  • Authenticator
    即認(rèn)證器,對(duì)用戶身份進(jìn)行認(rèn)證,Authenticator是一個(gè)接口,shiro提供ModularRealmAuthenticator實(shí)現(xiàn)類,通過ModularRealmAuthenticator基本上可以滿足大多數(shù)需求,也可以自定義認(rèn)證器。
  • Authorizer
    即授權(quán)器,用戶通過認(rèn)證器認(rèn)證通過,在訪問功能時(shí)需要通過授權(quán)器判斷用戶是否有此功能的操作權(quán)限。
  • realm
    即領(lǐng)域,相當(dāng)于datasource數(shù)據(jù)源,securityManager進(jìn)行安全認(rèn)證需要通過Realm獲取用戶權(quán)限數(shù)據(jù),比如:如果用戶身份數(shù)據(jù)在數(shù)據(jù)庫那么realm就需要從數(shù)據(jù)庫獲取用戶身份信息。
    注意:不要把realm理解成只是從數(shù)據(jù)源取數(shù)據(jù),在realm中還有認(rèn)證授權(quán)校驗(yàn)的相關(guān)的代碼。
  • SessionManager
    即會(huì)話管理,shiro框架定義了一套會(huì)話管理,它不依賴web容器的session,所以shiro可以使用在非web應(yīng)用上,也可以將分布式應(yīng)用的會(huì)話集中在一點(diǎn)管理,此特性可使它實(shí)現(xiàn)單點(diǎn)登錄。
  • SessionDAO
    即會(huì)話dao,是對(duì)session會(huì)話操作的一套接口,比如要將session存儲(chǔ)到數(shù)據(jù)庫,可以通過jdbc將會(huì)話存儲(chǔ)到數(shù)據(jù)庫。
  • CacheManager
    CacheManager即緩存管理,將用戶權(quán)限數(shù)據(jù)存儲(chǔ)在緩存,這樣可以提高性能。
  • Cryptography
    即密碼管理,shiro提供了一套加密/解密的組件,方便開發(fā)。比如提供常用的散列、加/解密等功能。

Shiro認(rèn)證流程

image.png

自定義Realm

認(rèn)證時(shí)需要自己實(shí)現(xiàn)realm去獲取特定的數(shù)據(jù),如驗(yàn)證賬號(hào)密碼等。

public class CustomRealm1 extends AuthorizingRealm {

    @Override
    public String getName() {
        return "customRealm1";
    }

    //支持UsernamePasswordToken
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    //認(rèn)證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        //從token中 獲取用戶身份信息
        String username = (String) token.getPrincipal();
        //拿username從數(shù)據(jù)庫中查詢
        //....
        //如果查詢不到則返回null
        if(!username.equals("zhang")){//這里模擬查詢不到
            return null;
        }

        //獲取從數(shù)據(jù)庫查詢出來的用戶密碼 
        String password = "123";//這里使用靜態(tài)數(shù)據(jù)模擬。。

        //返回認(rèn)證信息由父類AuthenticatingRealm進(jìn)行認(rèn)證
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                username, password, getName());

        return simpleAuthenticationInfo;
    }

    //授權(quán)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }
}

注意,在SimpleAuthenticationInfo中第一個(gè)參數(shù)是Object類型,即你可以把User對(duì)象存入,在后面可以通過SecurityUtils.getSubject().getPrincipal()獲取用戶信息。

認(rèn)證密碼加密

散列算法

一般用于生成一段文本的摘要信息,散列算法不可逆,將內(nèi)容可以生成摘要,無法將摘要轉(zhuǎn)成原始內(nèi)容。散列算法常用于對(duì)密碼進(jìn)行散列,常用的散列算法有MD5、SHA。

一般散列算法需要提供一個(gè)salt(鹽)與原始內(nèi)容生成摘要信息,這樣做的目的是為了安全性,比如:111111的md5值是:96e79218965eb72c92a549dd5a330112,拿著“96e79218965eb72c92a549dd5a330112”去md5破解網(wǎng)站很容易進(jìn)行破解,如果要是對(duì)111111和salt(鹽,一個(gè)隨機(jī)數(shù))進(jìn)行散列,這樣雖然密碼都是111111加不同的鹽會(huì)生成不同的散列值。
代碼如下:

//md5加密,不加鹽
        String password_md5 = new Md5Hash("111111").toString();
        System.out.println("md5加密,不加鹽="+password_md5);

        //md5加密,加鹽,一次散列
        String password_md5_sale_1 = new Md5Hash("111111", "eteokues", 1).toString();
        System.out.println("password_md5_sale_1="+password_md5_sale_1);
        String password_md5_sale_2 = new Md5Hash("111111", "uiwueylm", 1).toString();
        System.out.println("password_md5_sale_2="+password_md5_sale_2);
        //兩次散列相當(dāng)于md5(md5())

        //使用SimpleHash
        String simpleHash = new SimpleHash("MD5", "111111", "eteokues",1).toString();
        System.out.println(simpleHash);

在realm中使用

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {

        //用戶賬號(hào)
        String username = (String) token.getPrincipal();
        //根據(jù)用戶賬號(hào)從數(shù)據(jù)庫取出鹽和加密后的值
        //..這里使用靜態(tài)數(shù)據(jù)
        //如果根據(jù)賬號(hào)沒有找到用戶信息則返回null,shiro拋出異常“賬號(hào)不存在”

        //按照固定規(guī)則加密碼結(jié)果 ,此密碼 要在數(shù)據(jù)庫存儲(chǔ),原始密碼 是111111,鹽是eteokues
        String password = "cb571f7bd7a6f73ab004a70322b963d5";
        //鹽,隨機(jī)數(shù),此隨機(jī)數(shù)也在數(shù)據(jù)庫存儲(chǔ)
        String salt = "eteokues";

        //返回認(rèn)證信息
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                username, password, ByteSource.Util.bytes(salt),getName());


        return simpleAuthenticationInfo;
    }

Shiro授權(quán)

授權(quán)流程

image.png

授權(quán)方式

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

  • 編程式:通過寫if/else 授權(quán)代碼塊完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有權(quán)限
} else {
//無權(quán)限
}
  • 注解式:通過在執(zhí)行的Java方法上放置相應(yīng)的注解完成:
@RequiresRoles("admin")
public void hello() {
//有權(quán)限
}
  • JSP/GSP 標(biāo)簽:在JSP/GSP 頁面通過相應(yīng)的標(biāo)簽完成:
<shiro:hasRole name="admin">
<!— 有權(quán)限—>
</shiro:hasRole>

Permission 鑒權(quán)方式

我們了解到了 Shiro 的Authorization有三種方式,作為細(xì)粒度化的 Authorization,Permission 同樣也支持粗粒度的 Authorization 的三種方式即代碼判斷,注解,JSP頁面校驗(yàn)。

  • 代碼判斷/注解
@RequiresRoles("admin")
@RequiresPermissions("admin:view:*")
@RequestMapping(value="/admin")
public String AuthorizationOne () {
    Subject admin =SecurityUtils.getSubject();
    System.out.println("角色 " + admin.getPrincipal());
    admin.isPermitted("admin:view:*");
    System.out.println("角色 " + admin.getPrincipal()+" 是否擁有 admin:view:* 權(quán)限:"+admin.isPermitted("admin:view:*"));
    return "admin";
}
  • JSP 頁面校驗(yàn)
<!-- 只有 user:view:* 權(quán)限才能顯示一下內(nèi)容 -->
<shiro:hasPermission name="user:view:*">
    Only User has 'user:view:*' can access to those words
</shiro:hasPermission>
<br>
<!-- 只有 admin:view:* 權(quán)限才能顯示一下內(nèi)容 -->
<shiro:hasPermission name="admin:view:*">
    Only Admin has 'admin:view:*' can access to those words
</shiro:hasPermission>

Shiro Authorization 大致可以被概述為實(shí)現(xiàn)了角色授權(quán)和權(quán)限授權(quán)

  • 角色授權(quán):粗粒度授權(quán),為當(dāng)前Subject 做角色判定或賦予
  • 權(quán)限授權(quán):細(xì)粒度授權(quán),為當(dāng)前Role 做權(quán)限判定或賦予。
  • 在細(xì)粒度授權(quán)時(shí)要重分理解 資源標(biāo)識(shí)符:操作:對(duì)象實(shí)例ID 規(guī)則的定義的應(yīng)用的實(shí)際場(chǎng)景。

權(quán)限字符串規(guī)則

權(quán)限一般是以字符串的形式表示的,權(quán)限字符串的規(guī)則是:“資源標(biāo)識(shí)符:操作:資源實(shí)例標(biāo)識(shí)符”,意思是對(duì)哪個(gè)資源的哪個(gè)實(shí)例具有什么操作,“:”是資源/操作/實(shí)例的分割符,, 表示操作的分割,* 表示任意資源/操作/實(shí)例。
如下:

用戶創(chuàng)建權(quán)限:user:create,或user:create:*
用戶修改實(shí)例001的權(quán)限:user:update:001
用戶實(shí)例001的所有權(quán)限:user:*:001

資源-操作-實(shí)例

資源-操作-實(shí)例 是 Shiro 做細(xì)粒度鑒權(quán) persmission時(shí)的一種規(guī)則。

  • 擴(kuò)展
    默認(rèn)支持通配符權(quán)限字符串,: 表示資源/操作/實(shí)例的分割;, 表示操作的分割,* 表示任意資源/操作/實(shí)例。
  • 單個(gè)權(quán)限
    • user:query、user:edit。
    • 冒號(hào)是一個(gè)特殊字符,它用來分隔權(quán)限字符串的下一部件:第一部分是權(quán)限被操作的領(lǐng)域,第二部分是被執(zhí)行的操作。
    • 多個(gè)值:每個(gè)部件能夠保護(hù)多個(gè)值。因此,除了授予用戶 user:query和 user:edit 權(quán)限外,也可以簡(jiǎn)單地授予他們一個(gè):user:query, edit。
    • 還可以用 * 號(hào)代替所有的值,如:user:* , 也可以寫:*:query,表示某個(gè)用戶在所有的領(lǐng)域都有 query 的權(quán)限。
    • 例子
      • 單個(gè)資源多個(gè)權(quán)限 user:query user:add 多值 user:query,add
      • 單個(gè)資源所有權(quán)限 user:query,add,update,delete user:*
      • 所有資源某個(gè)權(quán)限 *:view
  • 實(shí)例級(jí)訪問控制
    • 規(guī)則: 資源標(biāo)識(shí)符:操作:對(duì)象實(shí)例 ID
    • 這種情況通常會(huì)使用三個(gè)部件:域、操作、被付諸實(shí)施的實(shí)例。如:user:edit:manager
    • 也可以使用通配符來定義,如:user:edit:、user::、user::manager
    • 部分省略通配符:缺少的部件意味著用戶可以訪問所有與之匹配的值,比如:user:edit 等價(jià)于 user:edit :、
      user 等價(jià)于 user:
      :*
    • 通配符只能從字符串的結(jié)尾處省略部件,也就是說 user:edit 并不等價(jià)于 user:*:edit
    • 例子
      • 單個(gè)實(shí)例的單個(gè)權(quán)限 printer:query:lp7200 printer:print:epsoncolor
        • 對(duì)資源printer的lp7200實(shí)例擁有query權(quán)限。
        • 對(duì)資源printer的epsoncolor實(shí)例擁有query權(quán)限。
      • 所有實(shí)例的單個(gè)權(quán)限 printer:print:*
        • 對(duì)資源printer的所有r實(shí)例擁有query權(quán)限。
      • 所有實(shí)例的所有權(quán)限 printer::
        • 對(duì)資源printer的1實(shí)例擁有所有權(quán)限。然后通過如下代碼判斷
          subject().checkPermissions(“printer:setting:1”, “printer:printe:2”);
      • 單個(gè)實(shí)例的所有權(quán)限 printer:*:lp7200
        • 對(duì)資源printer的lp7200實(shí)例擁有所有權(quán)限
      • 單個(gè)實(shí)例的多個(gè)權(quán)限 printer:query,print:lp7200
        • 對(duì)資源printer的lp7200實(shí)例擁有query,print權(quán)限

基于角色的授權(quán)

// 用戶授權(quán)檢測(cè) 基于角色授權(quán)
// 是否有某一個(gè)角色
System.out.println("用戶是否擁有一個(gè)角色:" + subject.hasRole("role1"));
// 是否有多個(gè)角色
System.out.println("用戶是否擁有多個(gè)角色:" + subject.hasAllRoles(Arrays.asList("role1", "role2")));

對(duì)應(yīng)的check方法:

subject.checkRole("role1");
subject.checkRoles(Arrays.asList("role1", "role2"));

基于資源授權(quán)

// 基于資源授權(quán)
System.out.println("是否擁有某一個(gè)權(quán)限:" + subject.isPermitted("user:delete"));
System.out.println("是否擁有多個(gè)權(quán)限:" + subject.isPermittedAll("user:create:1",    "user:delete"));

對(duì)應(yīng)的check方法:

subject.checkPermission("sys:user:delete");
subject.checkPermissions("user:create:1","user:delete");

自定義realm

與上邊認(rèn)證自定義realm一樣,大部分情況是要從數(shù)據(jù)庫獲取權(quán)限數(shù)據(jù),這里直接實(shí)現(xiàn)基于資源的授權(quán)。
在認(rèn)證章節(jié)寫的自定義realm類中完善doGetAuthorizationInfo方法,此方法需要完成:根據(jù)用戶身份信息從數(shù)據(jù)庫查詢權(quán)限字符串,由shiro進(jìn)行授權(quán)。

// 授權(quán)
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // 獲取身份信息
        String username = (String) principals.getPrimaryPrincipal();
        // 根據(jù)身份信息從數(shù)據(jù)庫中查詢權(quán)限數(shù)據(jù)
        //....這里使用靜態(tài)數(shù)據(jù)模擬
        List<String> permissions = new ArrayList<String>();
        permissions.add("user:create");
        permissions.add("user.delete");

        //將權(quán)限信息封閉為AuthorizationInfo

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for(String permission:permissions){
            simpleAuthorizationInfo.addStringPermission(permission);
        }

        return simpleAuthorizationInfo;
    }

自定義permission和RolePerminssion

通過addStringPermission 默認(rèn)是用Permission的實(shí)現(xiàn)類封裝的 當(dāng)然也可以實(shí)現(xiàn)自定義的Permission。

public class MyPermission implements Permission {

    String permissionCode;
    public MyPermission(String name) {
        permissionCode=name;
    }

    @Override
    public boolean implies(Permission permission) {
        //自定義比較
        // TODO Auto-generated method stub
        return false;
    }
}

當(dāng)我們調(diào)用subject.isPermitted("user:update")會(huì)調(diào)用將指令傳達(dá)給SecurityManager,SecurityManager 再將指令傳達(dá)給授權(quán)管理類Authorizer,Authorizer會(huì)通過reaml獲得授權(quán)信息SimpleAuthorizationInfo如果我們返回的授權(quán)信息擁有角色 會(huì)調(diào)用RolePermissionResolver實(shí)現(xiàn)類的方法 將角色的權(quán)限追加到SimpleAuthorizationInfo(默認(rèn)是沒有實(shí)現(xiàn)的)。

public class MyRolePermissionResolver  implements RolePermissionResolver{

    @Override
    public Collection<Permission> resolvePermissionsInRole(String roleString) {
        // TODO Auto-generated method stub
         return Arrays.asList((Permission)new MyPermission("menu:*")); 
    }

這里面是根據(jù)角色查詢權(quán)限

最終 遍歷SimpleAuthorizationInfo的權(quán)限信息 (我們的權(quán)限信息都封裝Permission接口實(shí)現(xiàn)類 調(diào)用implies方法進(jìn)行比較 如果比較成功返回true 表示授權(quán)通過)自定義Permission的好處就是我們可以自定義匹配規(guī)則。

@RequiresPermissions 注解說明

@RequiresAuthentication

驗(yàn)證用戶是否登錄,等同于方法subject.isAuthenticated() 結(jié)果為true時(shí)。

@RequiresUser

驗(yàn)證用戶是否被記憶,user有兩種含義:
一種是成功登錄的(subject.isAuthenticated() 結(jié)果為true);
另外一種是被記憶的(subject.isRemembered()結(jié)果為true)。

@RequiresGuest

驗(yàn)證是否是一個(gè)guest的請(qǐng)求,與@RequiresUser完全相反。
換言之,RequiresUser == !RequiresGuest。
此時(shí)subject.getPrincipal() 結(jié)果為null.

@RequiresRoles

例如:@RequiresRoles("aRoleName");
void someMethod();
如果subject中有aRoleName角色才可以訪問方法someMethod。如果沒有這個(gè)權(quán)限則會(huì)拋出異常AuthorizationException

@RequiresPermissions

例如: @RequiresPermissions({"file:read", "write:aFile.txt"} )
void someMethod();
要求subject中必須同時(shí)含有file:read和write:aFile.txt的權(quán)限才能執(zhí)行方法someMethod()。否則拋出異常AuthorizationException。

?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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