理解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)兩部分春弥,簡稱認(rèn)證授權(quán)。對(duì)于需要訪問控制的資源用戶首先經(jīng)過身份認(rèn)證叠荠,認(rèn)證通過后用戶具有該資源的訪問權(quán)限方可訪問匿沛。

身份認(rèn)證

判斷一個(gè)用戶是否為合法用戶的處理過程。最常用的簡單身份認(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)可簡單理解為 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)營報(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í)際場景。

權(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)限外,也可以簡單地授予他們一個(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)檢測 基于角色授權(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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瘪撇,隨后出現(xiàn)的幾起案子获茬,更是在濱河造成了極大的恐慌,老刑警劉巖设江,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锦茁,死亡現(xiàn)場離奇詭異,居然都是意外死亡叉存,警方通過查閱死者的電腦和手機(jī)码俩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歼捏,“玉大人稿存,你說我怎么就攤上這事⊥啵” “怎么了瓣履?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長练俐。 經(jīng)常有香客問我袖迎,道長,這世上最難降的妖魔是什么腺晾? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任燕锥,我火速辦了婚禮,結(jié)果婚禮上悯蝉,老公的妹妹穿的比我還像新娘归形。我一直安慰自己,他們只是感情好鼻由,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布暇榴。 她就那樣靜靜地躺著,像睡著了一般蕉世。 火紅的嫁衣襯著肌膚如雪蔼紧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天狠轻,我揣著相機(jī)與錄音奸例,去河邊找鬼。 笑死哈误,一個(gè)胖子當(dāng)著我的面吹牛哩至,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜜自,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼菩貌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了重荠?” 一聲冷哼從身側(cè)響起箭阶,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎戈鲁,沒想到半個(gè)月后仇参,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婆殿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年诈乒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆芦。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怕磨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出消约,到底是詐尸還是另有隱情肠鲫,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布或粮,位于F島的核電站导饲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏氯材。R本人自食惡果不足惜渣锦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浓体。 院中可真熱鬧泡挺,春花似錦、人聲如沸命浴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽生闲。三九已至媳溺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碍讯,已是汗流浹背悬蔽。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捉兴,地道東北人蝎困。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓录语,卻偏偏與公主長得像,于是被迫代替她去往敵國和親禾乘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子澎埠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 前言 本章我們來學(xué)習(xí)權(quán)限認(rèn)證,在開始前我們先明白一些基本的概念始藕。 主體(Subject):即訪問應(yīng)用的用戶蒲稳,在Sh...
    卑微幻想家閱讀 1,036評(píng)論 0 4
  • title: 初識(shí)Shirotags: shirocategories: shiro 若圖片無法顯示,請(qǐng)前往我的博...
    codingXiaxw閱讀 575評(píng)論 1 0
  • 今年春節(jié)伍派,三三給父母安排了個(gè)驚喜江耀,一次說走就走的旅行∷咧玻考慮到二老的舒適方便祥国,此次旅行采用了精品小團(tuán)跟團(tuán)游的...
    三三愛讀書閱讀 1,058評(píng)論 3 2
  • 20171220 復(fù)盤第25天 安之若素 學(xué)習(xí)是否可以改變命運(yùn)? 我不知道大家是怎么認(rèn)為學(xué)習(xí)這件事情的倍踪,講真...
    王薩怡閱讀 275評(píng)論 0 0
  • 周末系宫,小忙。早已習(xí)慣了連日陰冷的天氣建车,不曾想偶然抬頭扩借,卻看到窗外雪花飛舞。六瓣精靈缤至,先是片片飄灑潮罪,后來就急...
    梅子浠閱讀 334評(píng)論 0 1