![](http://static.javashuo.com/static/loading.gif)
寫在前面:
小夥伴兒們,你們好!上一篇咱們學了Shiro的身份認證——深刻淺出Shiro系列——身份認證java
此次讓咱們一塊兒來學習Shiro權限認證!git
思惟導圖:
![](http://static.javashuo.com/static/loading.gif)
1,Shiro 受權
受權,也叫訪問控制,即在應用中控制誰能訪問哪些資源(如訪問頁面/編輯數據/頁面操做等)。在受權中需瞭解的幾個關鍵對象:主體(Subject)、資源(Resou rce)、權限(Permission)、角色(Role )。程序員
主體:主體,即訪問應用的用戶,在Shiro中使用 Subject 表明該用戶。用戶只有受權後才容許訪問相應的資源。web
資源:在應用中用戶能夠訪問的任何東西,好比訪問 JSP 頁面、查看/編輯某些數據、訪問某個業務方法、打印文本等等都是資源。用戶只要受權後才能訪問。apache
權限:安全策略中的原子受權單位,經過權限咱們能夠表示在應用中用戶有沒有操做某個資源的權力。即權限表示在應用中用戶能不能訪問某個資源,如:訪問用戶列表頁面,查看/新增/修改/刪除用戶數據(即不少時候都是 CRUD(增查改刪)式權限控制)等。編程
如上能夠看出,權限表明了用戶有沒有操做某個資源的權利,即反映在某個資源上的操做允不容許,不反映誰去執行這個操做。因此後續還須要把權限賦予給用戶,即定義哪一個用戶容許在某個資源上作什麼操做(權限),Shiro 不會去作這件事情,而是由實現人員提供。swift
角色:角色表明了操做集合,能夠理解爲權限的集合,通常狀況下咱們會賦予用戶角色而不是權限,即這樣用戶能夠擁有一組權限,賦予權限時比較方便。典型的如:項目經理、技術總監、CTO、開發工程師等都是角色,不一樣的角色擁有一組不一樣的權限。安全
2,受權方式
Shiro 支持三種方式的受權:編程式,註解式和標籤式;這裏講一下編程式。微信
這裏咱們先將Shiro認證封裝成一個工具類ShiroUtil;編輯器
package com.java.common;
import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;
/** * ShiroUtil工具類 */public class ShiroUtil {
public static Subject login(String configFile,String userName,String password){ // 讀取配置文件,初始化SecurityManager工廠 Factory<SecurityManager> factory=new IniSecurityManagerFactory(configFile); // 獲取securityManager實例 SecurityManager securityManager=factory.getInstance(); // 把securityManager實例綁定到SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 獲得當前執行的用戶 Subject currentUser=SecurityUtils.getSubject(); // 建立token令牌,用戶名/密碼 UsernamePasswordToken token=new UsernamePasswordToken(userName, password); try{ // 身份認證 currentUser.login(token); System.out.println("身份認證成功!"); }catch(AuthenticationException e){ e.printStackTrace(); System.out.println("身份認證失敗!"); } return currentUser; }}
來看看程序結構:
編程式;
基於角色的訪問控制;
配置文件shiro_role.ini:
[users]
java=123,role1,role2
jack=123,role1
規則即:「用戶名=密碼,角色1,角色2」,若是須要在應用中判斷用戶是否有相應角色,就須要在相應的 Realm 中返回角色信息,也就是說 Shiro 不負責維護用戶-角色信息,須要應用提供。
測試類:
package com.java.shiro;
import com.java.common.ShiroUtil;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import java.util.Arrays;
public class RoleTest {
@Test
public void testHasRole() {
Subject currentUser= ShiroUtil.login("classpath:shiro_role.ini", "java", "123");
// Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "jack", "123");
//hasRole()方法判斷currentUser用戶是否有role1和role2角色
System.out.println(currentUser.hasRole("role1")?"有role1這個角色":"沒有role1這個角色");
//hasRoles()方法同時判斷currentUser用戶是否有多個角色
boolean []results=currentUser.hasRoles(Arrays.asList("role1","role2","role3"));
System.out.println(results[0]?"有role1這個角色":"沒有role1這個角色");
System.out.println(results[1]?"有role2這個角色":"沒有role2這個角色");
System.out.println(results[2]?"有role3這個角色":"沒有role3這個角色");
//hasAllRoles()方法判斷是否擁有全部角色
System.out.println(currentUser.hasAllRoles(Arrays.asList("role1","role2"))?"role1,role2這兩個角色都有":"role1,role2這個兩個角色不全有");
//currentUser.logout();
}
}
輸出結果:
![](http://static.javashuo.com/static/loading.gif)
基於權限的訪問控制;
配置文件shiro_permission.ini:
[users]
java=123,role1,role2
jack=123,role1
[roles]
role1=user:select
role2=user:add,user:update,user:delete
規則:「用戶名=密碼,角色 1,角色 2」「角色=權限 1,權限 2」,即首先根據用戶名找到角色,而後根據角色再找到權限;即角色是權限集合;Shiro 一樣不進行權限的維護,須要咱們經過 Realm 返回相應的權限信息。只須要維護「用戶——角色」之間的關係便可。
測試類:
package com.java.shiro;
import com.java.common.ShiroUtil;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class PermissionTest {
@Test
public void testIsPermitted() {
Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "java", "123");
// Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "jack", "123");
System.out.println(currentUser.isPermitted("user:select")?"有user:select這個權限":"沒有user:select這個權限");
System.out.println(currentUser.isPermitted("user:update")?"有user:update這個權限":"沒有user:update這個權限");
boolean results[]=currentUser.isPermitted("user:select","user:update","user:delete");
System.out.println(results[0]?"有user:select這個權限":"沒有user:select這個權限");
System.out.println(results[1]?"有user:update這個權限":"沒有user:update這個權限");
System.out.println(results[2]?"有user:delete這個權限":"沒有user:delete這個權限");
System.out.println(currentUser.isPermittedAll("user:select","user:update")?"有user:select,update這兩個權限":"user:select,update這兩個權限不全有");
currentUser.logout();
}
}
輸出結果:
![](http://static.javashuo.com/static/loading.gif)
到此基於資源的訪問控制(顯示角色)就完成了,也能夠叫基於權限的訪問控制,這種方式的通常規則是「資源標識符:操做」,便是資源級別的粒度;這種方式的好處就是若是要修改基本都是一個資源級別的修改,不會對其餘模塊代碼產生影響,粒度小。可是實現起來可能稍微複雜點,須要維護「用戶——角色,角色——權限(資源:操做)」之間的關係。
3,受權流程
![](http://static.javashuo.com/static/loading.gif)
流程以下:
-
首先調用 Subject.isPermitted*/hasRole*
接口,其會委託給 SecurityMana ger,而 SecurityManager 接着會委託給 Authorizer; -
Authorizer 是真正的受權者,若是咱們調用如 isPermitted(「user:view」),其首先會經過 PermissionResolver 把字符串轉換成相應的 Permission 實例; -
在進行受權以前,其會調用相應的 Real m 獲取 Subject 相應的角色/權限用於匹配傳入的角色/權限; -
Authorizer 會判斷 Realm 的角色/權限是否和傳入的匹配,若是有多個 Real m,會委託給 ModularRealmAuthori zer 進行循環判斷,若是匹配如 isPermitted*/hasRole*
會返回 true,不然返回 false 表示受權失敗。
文中源代碼已上傳至碼雲:
https://gitee.com/Huke-123/shiro_series
好了,今天就先分享到這裏了,下期繼續給你們帶來Shiro相關方面的學習!更多幹貨、優質文章,歡迎關注個人原創技術公衆號~
![](http://static.javashuo.com/static/loading.gif)
你點的每個在看,我都認真當成了喜歡
本文分享自微信公衆號 - 程序員的時光(gh_9211ec727426)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。