1. 程式人生 > >Shiro認證流程和授權流程

Shiro認證流程和授權流程

認證:

身份驗證,即在應用中誰能證明他就是他本人。一般提供如他們的身份ID一些標識資訊來表明他就是他本人,如提供身份證,使用者名稱/密碼來證明。
在shiro中,使用者需要提供principals (身份)和credentials(證明)給shiro,從而應用能驗證使用者身份:
principals:身份,即主體的標識屬性,可以是任何東西,如使用者名稱、郵箱等,唯一即可。一個主體可以有多個principals,但只有一個Primary principals,一般是使用者名稱/密碼/手機號。
credentials:證明/憑證,即只有主體知道的安全值,如密碼/數字證書等。
最常見的principals和credentials組合就是使用者名稱/密碼了。接下來先進行一個基本的身份認證。

另外兩個相關的概念是之前提到的Subject及Realm,分別是主體及驗證主體的資料來源。

Shiro認證流程

這裡寫圖片描述
1、首先呼叫Subject.login(token)進行登入,其會自動委託給Security Manager,呼叫之前必須通過SecurityUtils. setSecurityManager()設定;
2、SecurityManager負責真正的身份驗證邏輯;它會委託給Authenticator進行身份驗證;
3、Authenticator才是真正的身份驗證者,Shiro API中核心的身份認證入口點,此處可以自定義插入自己的實現;
4、Authenticator可能會委託給相應的AuthenticationStrategy進行多Realm身份驗證,預設ModularRealmAuthenticator會呼叫AuthenticationStrategy進行多Realm身份驗證;
5、Authenticator會把相應的token傳入Realm,從Realm獲取身份驗證資訊,如果沒有返回/丟擲異常表示身份驗證失敗了。此處可以配置多個Realm,將按照相應的順序及策略進行訪問。

授權:

授權,也叫訪問控制,即在應用中控制誰能訪問哪些資源(如訪問頁面/編輯資料/頁面操作等)。在授權中需瞭解的幾個關鍵物件:主體(Subject)、資源(Resource)、許可權(Permission)、角色(Role)。

主體

主體,即訪問應用的使用者,在Shiro中使用Subject代表該使用者。使用者只有授權後才允許訪問相應的資源。
資源
在應用中使用者可以訪問的任何東西,比如訪問JSP頁面、檢視/編輯某些資料、訪問某個業務方法、列印文字等等都是資源。使用者只要授權後才能訪問。
許可權
安全策略中的原子授權單位,通過許可權我們可以表示在應用中使用者有沒有操作某個資源的權力。即許可權表示在應用中使用者能不能訪問某個資源,如:
訪問使用者列表頁面
檢視/新增/修改/刪除使用者資料(即很多時候都是CRUD(增查改刪)式許可權控制)
列印文件等等。。。

如上可以看出,許可權代表了使用者有沒有操作某個資源的權利,即反映在某個資源上的操作允不允許,不反映誰去執行這個操作。所以後續還需要把許可權賦予給使用者,即定義哪個使用者允許在某個資源上做什麼操作(許可權),Shiro不會去做這件事情,而是由實現人員提供。

Shiro支援粗粒度許可權(如使用者模組的所有許可權)和細粒度許可權(操作某個使用者的許可權,即例項級別的),後續部分介紹。

Shiro授權流程

這裡寫圖片描述

1、首先呼叫Subject.isPermitted*/hasRole*介面,其會委託給SecurityManager,而SecurityManager接著會委託給Authorizer;
2、Authorizer是真正的授權者,如果我們呼叫如isPermitted(“user:view”),其首先會通過PermissionResolver把字串轉換成相應的Permission例項;
3、在進行授權之前,其會呼叫相應的Realm獲取Subject相應的角色/許可權用於匹配傳入的角色/許可權;
4、Authorizer會判斷Realm的角色/許可權是否和傳入的匹配,如果有多個Realm,會委託給ModularRealmAuthorizer進行迴圈判斷,如果匹配如isPermitted*/hasRole*會返回true,否則返回false表示授權失敗。

ModularRealmAuthorizer進行多Realm匹配流程:
1、首先檢查相應的Realm是否實現了實現了Authorizer;
2、如果實現了Authorizer,那麼接著呼叫其相應的isPermitted*/hasRole*介面進行匹配;
3、如果有一個Realm匹配那麼將返回true,否則返回false。

1、如果Realm進行授權的話,應該繼承AuthorizingRealm,其流程是:
(1)如果呼叫hasRole*,則直接獲取AuthorizationInfo.getRoles()與傳入的角色比較即可;
(2)首先如果呼叫如isPermitted(“user:view”),首先通過PermissionResolver將許可權字串轉換成相應的Permission例項,預設使用WildcardPermissionResolver,即轉換為萬用字元的WildcardPermission;
2、通過AuthorizationInfo.getObjectPermissions()得到Permission例項集合;通過AuthorizationInfo. getStringPermissions()得到字串集合並通過PermissionResolver解析為Permission例項;然後獲取使用者的角色,並通過RolePermissionResolver解析角色對應的許可權集合(預設沒有實現,可以自己提供);
3、接著呼叫Permission. implies(Permission p)逐個與傳入的許可權比較,如果有匹配的則返回true,否則false。