1. 程式人生 > >Shiro許可權認證

Shiro許可權認證

shiro許可權管理的框架

1.許可權管理的概念

基本上涉及到使用者參與的系統都要進行許可權管理,許可權管理屬於系統安全的範疇,許可權管理實現對使用者訪問系統的控制,按照安全規則或者安全策略控制使用者可以訪問而且只能訪問自己被授權的資源。許可權管理包括使用者身份認證和授權兩部分,簡稱**認證授權**。對於需要訪問控制的資源使用者首先經過身份認證,認證通過後使用者具有該資源的訪問許可權方可訪問。

2.認證

1.認證的概念

  • 認證:使用者訪問系統的控制

2.認證中抽象出的物件

  • subject :主體相當於之前的user,訪問系統的使用者,主體可以是使用者、程式等,進行認證的都稱為主體;

  • Principal:身份資訊,是主體(subject)進行身份認證的標識,標識必須具有唯一性,如使用者名稱、手機號、郵箱地址等,一個主體可以有多個身份,但是必須有一個主身份(Primary Principal)。

  • credential:憑證資訊,是隻有主體自己知道的安全資訊,如密碼、證書等.

3.授權

1.授權的概念

  • 授權,即訪問控制,控制誰能訪問哪些資源。主體進行身份認證後需要分配許可權方可訪問系統的資源,對於某些資源沒有許可權是無法訪問的。

2.授權中抽象物件

  • Who,即主體(Subject),主體需要訪問系統中的資源。

  • What,即資源(Resource),如系統選單、頁面、按鈕、類方法、系統商品資訊等。資源包括資源型別和資源例項,比如商品資訊為資源型別,型別為t01的商品為資源例項,編號為001的商品資訊也屬於資源例項。

  • How,許可權/許可(Permission),規定了主體對資源的操作許可,許可權離開資源沒有意義,如使用者查詢許可權、使用者新增許可權、某個類方法的呼叫許可權、編號為001使用者的修改許可權等,通過許可權可知主體對哪些資源都有哪些操作許可。許可權分為粗顆粒和細顆粒,粗顆粒許可權是指對資源型別的許可權,細顆粒許可權是對資源例項的許可權。

4.許可權模型

主體(賬號、密碼)

資源(資源名稱、訪問地址)

許可權(許可權名稱、資源id

角色(角色名稱)

角色和許可權關係(角色id、許可權id

主體和角色關係(主體id、角色id

 

 

通常企業開發中將資源和許可權表合併為一張許可權表,如下:

 

資源(資源名稱、訪問地址)

 

許可權(許可權名稱、資源id

 

合併為:

 

許可權(許可權名稱、資源名稱、資源訪問地址)

 

 

 

上圖常被稱為許可權管理的通用模型,不過企業在開發中根據系統自身的特點還會對上圖進行修改,但是使用者、角色、許可權、使用者角色關係、角色許可權關係是需要去理解的。

 

5.許可權控制的方案

1.基於角色的許可權控制

RBAC基於角色的訪問控制(Role-Based Access Control)是以角色為中心進行訪問控制,比如:主體的角色為總經理可以查詢企業運營報表,查詢員工工資資訊等,訪問控制流程如下:

 

if(主體.hasRole("總經理角色id")){

查詢工資

}

2.基於資源的許可權控制

RBAC基於資源的訪問控制(Resource-Based Access Control)是以資源為中心進行訪問控制,比如:主體必須具有查詢工資許可權才可以查詢員工工資資訊等,訪問控制流程如下:

if(主體.hasRole("查詢工資的許可權")){

查詢工資

}

6.什麼是shiro

Shiro是apache旗下一個開源框架,它將軟體系統的安全認證相關的功能抽取出來,實現使用者身份認證,許可權授權、加密、會話管理等功能,組成了一個通用的安全認證框架.

7.為什麼要學shiro

既然shiro將安全認證相關的功能抽取出來組成一個框架,使用shiro就可以非常快速的完成認證、授權等功能的開發,降低系統成本。shiro使用廣泛,shiro可以執行在web應用,非web應用,叢集分散式應用中越來越多的使用者開始使用shiro。java領域中spring security(原名Acegi)也是一個開源的許可權管理框架,但是spring security依賴spring執行,而shiro就相對獨立,最主要是因為shiro使用簡單、靈活,所以現在越來越多的使用者選擇shiro。

8.shiro的核心架構圖

 

 

9.shiro的第一個程式

1.匯入jar

<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-core</artifactId>
 <version>1.3.2</version>
</dependency>

2.第一個認證的程式

//獲取安全管理器工廠
       IniSecurityManagerFactory iniSecurityManagerFactory=new IniSecurityManagerFactory("classpath:shiro.ini");
       //獲取安全管理器
       SecurityManager securityManager=iniSecurityManagerFactory.getInstance();

        SecurityUtils.setSecurityManager(securityManager);

       //獲取主體物件
       Subject subject = SecurityUtils.getSubject();
       //token就是使用者的令牌 包含使用者的身份資訊和憑證資訊
       AuthenticationToken token=new UsernamePasswordToken("zhangsan","1234567");

       try {
           subject.login(token);
      } catch (AuthenticationException e) {
           e.printStackTrace();
      }

       boolean authenticated = subject.isAuthenticated();

3.配置檔案

[users]
zhangsan=123456
lisi=123456

注意:shiro中主體是否認證成功是通過拋異常的形式體現的,一般會丟擲兩個異常

  • UnknownAccountException 賬號異常

  • IncorrectCredentialsException 密碼異常

10.shiro認證連線資料庫

1.原始碼追蹤中出現的關鍵物件

AuthenticatingRealm  //抽象類
   //3.關鍵屬性 該屬性為憑證匹配器
   CredentialsMatcher credentialsMatcher;
   //1.該方法為抽象方法 其作用使用來獲取資料
   protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
SimpleAccountRealm
//2.實現了AuthenticatingRealm抽象方法,用來獲取配置檔案中的使用者資訊,該類不做資料比對
SimpleCredentialsMatcher
//4.shiro中預設的憑證匹配器
 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
       Object tokenCredentials = this.getCredentials(token);
       Object accountCredentials = this.getCredentials(info);
       return this.equals(tokenCredentials, accountCredentials);
  }

2.連線資料庫

1.開發自定義realm
public class MyRealm extends AuthenticatingRealm {
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       //略 資料操作 並且根據相應格式返回 不做比對
  }
}
2.告知shiro要使用自定義realm
[main]
#自定義 realm
customRealm=com.baizhi.day1.MyRealm
#將realm設定到securityManager
securityManager.realms=$customRealm

注意:需要匯入一個jar

<dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.2</version>
</dependency>

11.shiro的加密認證方式

1.realm返回密文資料

public class MyRealm extends AuthenticatingRealm {
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       AuthenticationInfo authenticationInfo =authenticationInfo = new SimpleAuthenticationInfo("zhangsan", "3d53b73c485f523ef2fe45f2b8dd3c58", ByteSource.Util.bytes("ABCD"), this.getName());
       return authenticationInfo;
  }
}

2.修改配置檔案,加入憑證匹配器的相關配置

[main]
#自定義憑證匹配器
hashedCredentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher

#自定義 realm
customRealm=com.baizhi.day1.MyRealm
#憑證匹配器告訴誰
customRealm.credentialsMatcher=$hashedCredentialsMatcher
hashedCredentialsMatcher.hashAlgorithmName=MD5
hashedCredentialsMatcher.hashIterations=1024
#將realm設定到securityManager
securityManager.realms=$customRealm

12.授權

1.授權資料來源於資料庫

public class MyRealm extends AuthorizingRealm {
   //獲取資料 獲取認證的資料
   protected  AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
       //資料庫操作   基於身份資訊查主體
       
  }

    //獲取資料 獲取授權的資料
   protected  AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1){
        //資料庫操作   基於身份資訊查主體   基於主體查角色   基於角色查許可權
     
  }
   
}

2.java環境下授權的api

  • 基於角色

                //判斷當前主體是否包含此角色
               boolean b = subject.hasRole("super");
               List<String> list = Arrays.asList("super", "admin");
               //判斷當前主體是否包含某個角色
               boolean[] booleans = subject.hasRoles(list);
               //判斷當前主體是否包含全部的角色
               boolean b = subject.hasAllRoles(list);
  • 基於資源

                boolean b = subject.isPermitted("admin:delete");
               String[] strs={"admin:delete", "admin:add"};
               boolean[] permitted = subject.isPermitted(strs);
               boolean permittedAll = subject.isPermittedAll(strs);

3.許可權的識別符號

許可權字串的規則是:“資源識別符號:操作:資源例項識別符號”,意思是對哪個資源的哪個例項具有什麼操作,“:”是資源/操作/例項的分割符,許可權字串也可以使用*萬用字元。

例子:

  • 使用者建立許可權:user:create,或user:create:*

  • 使用者修改例項001的許可權:user:update:001

  • 使用者例項001的所有許可權:user:*:001

13.springboot環境下的認證和授權

1.相關的jar
    <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-core</artifactId>
           <version>1.3.2</version>
       </dependency>
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-web</artifactId>
           <version>1.3.2</version>
       </dependency>
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-ehcache</artifactId>
           <version>1.3.2</version>
       </dependency>
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-spring</artifactId>
           <version>1.3.2</version>
       </dependency>
2.配置shrio的核心過濾器
@Configuration
public class ShiroFilterConf {
   //shiro過濾器的配置
   @Bean
   public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       //多個過濾器 AnonymousFilter 匿名過濾器   anon
       // FormAuthenticationFilter 認證過濾器 authc
       Map<String, String> map = new HashMap<>();
       map.put("/user/loginUser", "anon");
       map.put("/index.jsp", "anon");
       map.put("/**", "authc");
       //設定登入入口的路徑
       shiroFilterFactoryBean.setLoginUrl("/main/login.jsp");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
       return shiroFilterFactoryBean;
  }
  //shiro的核心物件 安全管理器
   @Bean
   public SecurityManager getSecurityManager(Realm realm) {
       DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
       securityManager.setRealm(realm);
       return securityManager;
  }
   //自定義realm
   @Bean
   public Realm getRealm(CredentialsMatcher credentialsMatcher) {
       MyRealm myRealm = new MyRealm();
       myRealm.setCredentialsMatcher(credentialsMatcher);
       return myRealm;
  }
  //選擇HashedCredentialsMatcher 憑證匹配器
   @Bean
   public CredentialsMatcher getCredentialsMatcher() {
       HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
       hashedCredentialsMatcher.setHashAlgorithmName("md5");
       hashedCredentialsMatcher.setHashIterations(1024);
       return hashedCredentialsMatcher;
  }

}
3.shiro中相關的標籤
先匯入標籤庫
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

<shiro:principal></shiro:principal> //使用者的身份資訊
<shiro:authenticated></shiro:authenticated> //認證成功 執行標籤體的內容
<shiro:notAuthenticated></shiro:notAuthenticated> //未認證 執行標籤體內容
//基於角色的許可權管理
<shiro:hasRole name="super"></shiro:hasRole>
<shiro:hasAnyRoles name="admin,super"></shiro:hasAnyRoles>
//基於資源的許可權管理
<shiro:hasPermission name="user:delete"></shiro:hasPermission>