12.30 Shiro授權及Realm的使用

授權,也稱訪問控制,在應用中控制誰能訪問哪些資源(如訪問頁面、編輯數據、等)。在授權中需瞭解的幾個關鍵詞:主體(subject)、資源(resource)、權限(permission)、角色(role)。

主體

主體,訪問應用的用戶,在 Shiro 中使用 Subject 代表該用戶。用戶只有授權後才允許訪問相應的資源。

資源

在應用中用戶可以訪問的任何東西,比如訪問 JSP 頁面、CRUD數據、訪問接口、打印等等都是資源。用戶只有通過授權後才能訪問。

權限

通過權限我們可以表示在應用中用戶有沒有操作某個資源的權力。即權限表示在應用中用戶能不能訪問某個資源,如: 訪問用戶列表頁面、CRUD數據、打印文檔等。

角色

角色代表了用戶操作權限集合。一般情況下我們會賦予用戶角色而不是權限,即這樣用戶可以擁有多個權限。如:項目經理、技術總監、部門經理、主管等都是角色,不同的角色擁有多個不同的權限。

隱式角色:

直接通過角色來驗證用戶有沒有操作權限,在實際應用中技術總監、主管可以使用打印機,假設某天不允許主管使用打印機,此時需要從應用中刪除相應邏輯代碼。粒度較粗。

顯示角色:

在程序中通過權限控制誰能訪問某個資源,即角色擁有多個權限,這樣假設哪個角色不能訪問某個資源,只需要從角色擁有權限中移除即可。無須修改多處代碼,即粒度是以資源-實例為單位的;粒度較細。

1)編程式:通過寫 if/else 授權代碼塊完成。

//1. 從 PrincipalCollection 中來獲取登錄用戶的信息

Object principal = arg0.getPrimaryPrincipal();

//2. 利用登錄的用戶的信息來獲取當前用戶的角色或權限

Set<string> roles = new HashSet<>();/<string>

roles.add("user");

if("admin".equals(principal)){

roles.add("admin");

}

/

2)註解式:通過在執行的方法上註解完成。

@RequiresRoles("user")

public void user() {

//有權限

}

3)JSP標籤:在 JSP頁面通過相應的標籤完成。(jsp已過時了,現在是前後端分離)

<hasrole>

1) 基於角色的訪問控制。

在 ini 配置文件配置用戶擁有的角色,格式:用戶名=密碼,角色1,角色2。

[users]

zhang=123456,role1,role2

wang=123456,role1

Shiro 提供了 hasRole/hasAllRoles用於判斷用戶是否擁有某個角色。

// 1、獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager

Factory<org.apache.shiro.mgt.securitymanager> factory =/<org.apache.shiro.mgt.securitymanager>

new IniSecurityManagerFactory("classpath:shiro.ini");

// 2、得到SecurityManager實例 並綁定給SecurityUtils

org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();

SecurityUtils.setSecurityManager(securityManager);

// 3、得到Subject及創建用戶名/密碼身份驗證Token

Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123456");

try {

// 4、登錄,身份驗證

subject.login(token);

} catch (AuthenticationException e) {

// 5、身份驗證失敗

logger.info("用戶名 、密碼錯誤");

}

if(subject.hasRole("role1")){

logger.info(token.getUsername()+" has role1");

}else{

logger.info(token.getUsername()+" hasn't role1");

}

2) 基於資源(權限)的訪問控制

在 ini 配置文件配置用戶擁有的角色及角色-權限關係,格式:"角色=權限 1,權限 2"。

首先根據用戶名找到角色,然後根據角色再找到權限,即角色是權限的組合。

[users]

zhang=123456,role1,role2

wang=123456,role1

[roles]

role1=user:create,user:update

role2=user:create,user:delete

Shiro 提供了 isPermitted 和 isPermittedAll 用於判斷用戶是否擁有某個權限或所有權限。

if(subject.isPermitted("user:create")){

logger.info(token.getUsername()+" has user:create");

}else{

logger.info(token.getUsername()+" hasn't user:create");

}

Shiro授權及Realm的使用

1)首先調用 subject.isPermitted*/hasRole*接口,其會委託給 SecurityManager,而 SecurityManager 接著會委託給 Authorizer。

2)Authorizer 是真正的授權者,如果我們調用如 isPermitted("user:view"),其首先會通過 PermissionResolver 把字符串轉換成相應的 Permission 實例;

在進行授權之前,其會調用相應的 Realm 獲取 Subject 相應的角色、權限用於匹配傳入的角色、權限;

3) Authorizer 會判斷 Realm 的角色、權限是否和傳入的匹配,如果有多個 Realm,會委託給 ModularRealmAuthorizer 進行循環判斷,如果匹配如 isPermitted*/hasRole* 會返回 true,否則返回 false 表示授權失敗。

ModularRealmAuthorizer 進行多 Realm 匹配流程

1)首先檢查相應的 Realm 是否實現了實現了 Authorizer;

2)如果實現了 Authorizer,那麼接著調用其相應的 isPermitted*/hasRole* 接口進行匹配;

3)如果有一個 Realm 匹配那麼將返回 true,否則返回 false。

1、自定義類JdbcRealm繼續父AuthorizingRealm,重寫doGetAuthorizationInfo授權方法,根據授權的用戶在數據庫中查詢所擁有的角色、權限。

Shiro授權及Realm的使用

2、 當我們調用hasRole("普通員工")方法時,Authorizer 會調用doGetAuthorizationInfo()方法進行授權,判斷 Realm 的角色、權限是否和傳入的匹配,如果匹配,hasRole("普通員工")返回true,否則返回false。

Shiro授權及Realm的使用

3、 測試結果

Shiro授權及Realm的使用


分享到:


相關文章: