1. 程式人生 > 實用技巧 >Shiro安全框架入門學習

Shiro安全框架入門學習

Shiro官方網址:http://shiro.apache.org/

1、Shiro安全框架簡介,什麼是Shiro。

  1)、Apache的強大靈活的開源安全框架。
  2)、認證、授權、企業會話管理、安全加密。

2、Shiro和Spring Security的比較。

  1)、Shiro更加簡單和靈活,可以脫離Spring,粒度較粗。
  2)、Spring Security更加複雜和笨重,不可脫離Spring,粒度更細。

3、Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易於理解的API,您可以快速、輕鬆地獲得任何應用程式,從最小的移動應用程式到最大的網路和企業應用程式。

Authenticator:認證器,管理著登陸和登出。
Authorizer:授權器,管理主題擁有那些許可權。
Session Manager:Session管理器。
Session DAO:提供了Session的增加、修改、刪除、查詢操作。
Cache Manager:快取管理器,可以快取角色資料、許可權資料。
Pluggable Realms:可以理解為Shiro和資料庫之前的橋樑,shiro獲取角色資訊、許可權資訊都是通過Realms來獲取的。

4、三個核心元件:Subject, SecurityManager 和 Realms。

  1)、Subject:即“當前操作使用者”。但是,在Shiro中,Subject這一概念並不僅僅指人,也可以是第三方程序、後臺帳戶(Daemon Account)或其他類似事物。它僅僅意味著“當前跟軟體互動的東西”。Subject代表了當前使用者的安全操作,SecurityManager則管理所有使用者的安全操作。


  2)、SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部元件例項,並通過它來提供安全管理的各種服務。
  3)、Realm: Realm充當了Shiro與應用安全資料間的“橋樑”或者“聯結器”。也就是說,當對使用者執行認證(登入)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查詢使用者及其許可權資訊。從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了資料來源的連線細節,並在需要時將相關資料提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。

  Shiro內建了可以連線大量安全資料來源(又名目錄)的Realm,如LDAP、關係資料庫(JDBC)、類似INI的文字配置資源以及屬性檔案等。如果預設的Realm不能滿足需求,你還可以插入代表自定義資料來源的自己的Realm實現。

5、Shiro的認證、認證過程。

  Shiro中的SecurityManager是用來提供安全服務的,如果做Shiro認證的時候,首先要建立SecurityManager物件的,構建SecurityManager環境。然後是由主體Subject提交認證請求,主體提交認證請求到SecurityManager認證,SecurityManager是使用的Authenticator做認證的,Authenticator做認證的時候通過Realm來獲取認證的資料,進而由Realm做最終的認證。

6、簡單測試Shiro的認證、認證過程。首先引入shiro的依賴包,pom.xml如下所示:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 5          http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6     <parent>
 7         <artifactId>shiro</artifactId>
 8         <groupId>com.bie</groupId>
 9         <version>1.0-SNAPSHOT</version>
10     </parent>
11     <modelVersion>4.0.0</modelVersion>
12 
13     <artifactId>shiro-test</artifactId>
14 
15     <!-- 首先引入shiro的包 -->
16     <dependencies>
17         <!-- shiro的核心包 -->
18         <dependency>
19             <groupId>org.apache.shiro</groupId>
20             <artifactId>shiro-core</artifactId>
21             <version>1.2.2</version>
22         </dependency>
23 
24         <!-- 單元測試junit -->
25         <dependency>
26             <groupId>junit</groupId>
27             <artifactId>junit</artifactId>
28             <version>4.12</version>
29         </dependency>
30     </dependencies>
31 
32 </project>

認證的步驟,如下所示:

 1 package com.bie.test;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.UsernamePasswordToken;
 5 import org.apache.shiro.mgt.DefaultSecurityManager;
 6 import org.apache.shiro.realm.SimpleAccountRealm;
 7 import org.apache.shiro.subject.Subject;
 8 import org.junit.Before;
 9 import org.junit.Test;
10 
11 /**
12  * shiro認證測試
13  *
14  * @ProjectName: shiro
15  * @Package: com.bie.test
16  * @ClassName: AuthenticationTest
17  * @Author: biehl
18  * @Description: ${description}
19  * @Date: 2020/8/6 11:19
20  * @Version: 1.0
21  */
22 public class AuthenticationTest {
23 
24     // 建立一個簡單賬戶Realm
25     private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
26 
27     /**
28      * 測試執行之前執行該方法
29      */
30     @Before
31     public void add() {
32         simpleAccountRealm.addAccount("admin", "123456");
33     }
34 
35     @Test
36         public void testAuthentication() {
37         // 1、認證第一步,構建SecurityManager環境
38         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
39         // 將simpleAccountRealm設定到SecurityManager環境中
40         defaultSecurityManager.setRealm(simpleAccountRealm);
41 
42         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
43         // 設定SecurityManager環境
44         SecurityUtils.setSecurityManager(defaultSecurityManager);
45         Subject subject = SecurityUtils.getSubject();
46 
47         // 3、第三步,提交認證
48         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
49         subject.login(token);
50 
51         // 4、第四步,Realm驗證
52         boolean authenticated = subject.isAuthenticated();
53         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
54 
55         // 5、第五步,登陸之後可以進行退出
56         subject.logout();
57         boolean authenticated2 = subject.isAuthenticated();
58         System.out.println("isAuthenticated是否進行了認證:" + authenticated2);
59 
60     }
61 
62 }

專案結構和執行結果,如下所示:

7、Shiro的授權過程,如下所示:

實現程式碼,如下所示:

 1 package com.bie.test;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.UsernamePasswordToken;
 5 import org.apache.shiro.mgt.DefaultSecurityManager;
 6 import org.apache.shiro.realm.SimpleAccountRealm;
 7 import org.apache.shiro.subject.Subject;
 8 import org.junit.Before;
 9 import org.junit.Test;
10 
11 /**
12  * shiro認證測試
13  *
14  * @ProjectName: shiro
15  * @Package: com.bie.test
16  * @ClassName: AuthenticationTest
17  * @Author: biehl
18  * @Description: ${description}
19  * @Date: 2020/8/6 11:19
20  * @Version: 1.0
21  */
22 public class AuthenticationTest {
23 
24     // 建立一個簡單賬戶Realm
25     private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
26 
27     /**
28      * 測試執行之前執行該方法
29      */
30     @Before
31     public void add() {
32         // 設定賬號密碼
33         // simpleAccountRealm.addAccount("admin", "123456");
34         // 設定賬號密碼,角色(既是管理員角色、也是user普通使用者角色)
35         simpleAccountRealm.addAccount("admin", "123456", "admin", "user");
36     }
37 
38     @Test
39     public void testAuthentication() {
40         // 1、認證第一步,構建SecurityManager環境
41         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
42         // 將simpleAccountRealm設定到SecurityManager環境中
43         defaultSecurityManager.setRealm(simpleAccountRealm);
44 
45         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
46         // 設定SecurityManager環境
47         SecurityUtils.setSecurityManager(defaultSecurityManager);
48         Subject subject = SecurityUtils.getSubject();
49 
50         // 3、第三步,提交認證
51         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
52         subject.login(token);
53 
54         // 4、第四步,Realm驗證
55         boolean authenticated = subject.isAuthenticated();
56         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
57 
58         // 5、第五步,認證結束開始檢查使用者是否具備此角色
59         subject.checkRole("admin");
60         System.out.println("admin使用者具備該admin角色!");
61         // checkRoles檢查當前的主體s是否具備引數裡面所有的角色資料
62         subject.checkRoles("admin", "user");
63         System.out.println("admin使用者具備該admin、user角色!");
64     }
65 
66 }

8、Shiro內建的Realm,比如 IniRealm、JdbcRealm。

8.1、Shiro內建的IniRealm,可以配合.ini配置檔案來設定賬號,設定角色和賬號的繫結,設定許可權等功能。

 1 package com.bie.realm;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.UsernamePasswordToken;
 5 import org.apache.shiro.mgt.DefaultSecurityManager;
 6 import org.apache.shiro.realm.text.IniRealm;
 7 import org.apache.shiro.subject.Subject;
 8 import org.junit.Test;
 9 
10 /**
11  * @ProjectName: shiro
12  * @Package: com.bie.realm
13  * @ClassName: IniRealmTest
14  * @Author: biehl
15  * @Description: ${description}
16  * @Date: 2020/8/6 11:53
17  * @Version: 1.0
18  */
19 public class IniRealmTest {
20 
21     @Test
22     public void testAuthentication() {
23         // 0、建立一個IniRealm
24         IniRealm iniRealm = new IniRealm("classpath:user.ini");
25 
26         // 1、認證第一步,構建SecurityManager環境
27         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
28         defaultSecurityManager.setRealm(iniRealm);
29 
30         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
31         // 設定SecurityManager環境
32         SecurityUtils.setSecurityManager(defaultSecurityManager);
33         Subject subject = SecurityUtils.getSubject();
34 
35         // 3、第三步,提交認證
36         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
37         subject.login(token);
38 
39         // 4、第四步,Realm驗證
40         boolean authenticated = subject.isAuthenticated();
41         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
42 
43         // 5、檢查角色,檢查管理員的角色,給使用者admin配備角色admin
44         subject.checkRole("admin");
45         System.out.println("檢查管理員admin!");
46 
47         // 6、檢查許可權,檢查admin角色是否擁有使用者刪除的許可權
48         subject.checkPermission("user:delete");
49         System.out.println("檢查管理員擁有使用者刪除user:delete的許可權!");
50 
51         subject.checkPermission("user:update");
52         subject.checkPermission("user:select");
53         subject.checkPermission("user:insert");
54         System.out.println("檢查管理員擁有使用者刪除user:delete,user:update,user:select,user:insert的許可權!");
55     }
56 
57 }

user.ini配置檔案,如下所示:

1 [users]
2 admin=123456,admin
3 [roles]
4 admin=user:delete,user:update,user:select,user:insert

8.2、Shiro內建的JdbcRealm,如果使用預設的資料表結構,可以直接設定賬號,設定角色和賬號的繫結,設定許可權等功能。

 1 <!-- mysql驅動包 -->
 2 <dependency>
 3     <groupId>mysql</groupId>
 4     <artifactId>mysql-connector-java</artifactId>
 5     <version>5.1.46</version>
 6 </dependency>
 7 <!-- 資料來源 -->
 8 <dependency>
 9     <groupId>com.alibaba</groupId>
10     <artifactId>druid</artifactId>
11     <version>1.1.18</version>
12 </dependency>

shiro預設使用的資料表結構,這裡新增了幾條資料,如下所示:

 1 /*
 2  Navicat Premium Data Transfer
 3 
 4  Source Server         : mysql_localhost
 5  Source Server Type    : MySQL
 6  Source Server Version : 50720
 7  Source Host           : localhost:3306
 8  Source Schema         : test
 9 
10  Target Server Type    : MySQL
11  Target Server Version : 50720
12  File Encoding         : 65001
13 
14  Date: 06/08/2020 14:42:35
15 */
16 
17 SET NAMES utf8mb4;
18 SET FOREIGN_KEY_CHECKS = 0;
19 
20 -- ----------------------------
21 -- Table structure for roles_permissions
22 -- ----------------------------
23 DROP TABLE IF EXISTS `roles_permissions`;
24 CREATE TABLE `roles_permissions`  (
25   `id` int(11) NOT NULL AUTO_INCREMENT,
26   `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
27   `permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
28   PRIMARY KEY (`id`) USING BTREE
29 ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
30 
31 -- ----------------------------
32 -- Records of roles_permissions
33 -- ----------------------------
34 INSERT INTO `roles_permissions` VALUES (1, 'admin', 'user:select');
35 INSERT INTO `roles_permissions` VALUES (2, 'admin', 'user:insert');
36 INSERT INTO `roles_permissions` VALUES (3, 'admin', 'user:delete');
37 INSERT INTO `roles_permissions` VALUES (4, 'admin', 'user:update');
38 
39 -- ----------------------------
40 -- Table structure for user_roles
41 -- ----------------------------
42 DROP TABLE IF EXISTS `user_roles`;
43 CREATE TABLE `user_roles`  (
44   `id` int(11) NOT NULL AUTO_INCREMENT,
45   `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
46   `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
47   PRIMARY KEY (`id`) USING BTREE
48 ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
49 
50 -- ----------------------------
51 -- Records of user_roles
52 -- ----------------------------
53 INSERT INTO `user_roles` VALUES (1, 'admin', 'admin');
54 INSERT INTO `user_roles` VALUES (2, 'admin', 'user');
55 
56 -- ----------------------------
57 -- Table structure for users
58 -- ----------------------------
59 DROP TABLE IF EXISTS `users`;
60 CREATE TABLE `users`  (
61   `id` int(11) NOT NULL AUTO_INCREMENT,
62   `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
63   `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
64   PRIMARY KEY (`id`) USING BTREE
65 ) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
66 
67 -- ----------------------------
68 -- Records of users
69 -- ----------------------------
70 INSERT INTO `users` VALUES (3, 'admin', '123456');
71 INSERT INTO `users` VALUES (4, '張三', '123456');
72 INSERT INTO `users` VALUES (5, '李四', '123456');
73 
74 SET FOREIGN_KEY_CHECKS = 1;

JdbcRealm的案例程式碼,如下所示:

 1 package com.bie.realm;
 2 
 3 import com.alibaba.druid.pool.DruidDataSource;
 4 import org.apache.shiro.SecurityUtils;
 5 import org.apache.shiro.authc.UsernamePasswordToken;
 6 import org.apache.shiro.mgt.DefaultSecurityManager;
 7 import org.apache.shiro.realm.jdbc.JdbcRealm;
 8 import org.apache.shiro.subject.Subject;
 9 import org.junit.Test;
10 
11 /**
12  * @ProjectName: shiro
13  * @Package: com.bie.realm
14  * @ClassName: IniRealmTest
15  * @Author: biehl
16  * @Description: ${description}
17  * @Date: 2020/8/6 11:53
18  * @Version: 1.0
19  */
20 public class JdbcRealmTest {
21 
22     // 設定資料來源
23     DruidDataSource druidDataSource = new DruidDataSource();
24 
25     {
26         druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
27         druidDataSource.setUsername("root");
28         druidDataSource.setPassword("123456");
29     }
30 
31 
32     @Test
33     public void testAuthentication() {
34         // 設定JdbcRealm
35         JdbcRealm jdbcRealm = new JdbcRealm();
36         // 設定jdbc的資料來源
37         jdbcRealm.setDataSource(druidDataSource);
38         // 設定許可權的開關,預設是false,設定為true才可以查詢許可權資料的。
39         jdbcRealm.setPermissionsLookupEnabled(true);
40 
41         // 1、認證第一步,構建SecurityManager環境
42         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
43         // 設定Realm
44         defaultSecurityManager.setRealm(jdbcRealm);
45 
46         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
47         // 設定SecurityManager環境
48         SecurityUtils.setSecurityManager(defaultSecurityManager);
49         Subject subject = SecurityUtils.getSubject();
50 
51         // 3、第三步,提交認證
52         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
53         subject.login(token);
54 
55         // 4、第四步,Realm驗證
56         boolean authenticated = subject.isAuthenticated();
57         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
58 
59         // 5、檢查角色,檢查管理員的角色,給使用者admin配備角色admin
60         subject.checkRole("admin");
61         System.out.println("檢查管理員admin!");
62         subject.checkRoles("admin", "user");
63         System.out.println("檢查管理員admin、普通使用者角色user!");
64 
65         // 6、檢查許可權,檢查admin角色是否擁有使用者刪除的許可權
66         subject.checkPermission("user:delete");
67         System.out.println("檢查管理員擁有使用者刪除user:delete的許可權!");
68 
69         subject.checkPermission("user:update");
70         subject.checkPermission("user:select");
71         subject.checkPermission("user:insert");
72         System.out.println("檢查管理員擁有使用者刪除user:delete,user:update,user:select,user:insert的許可權!");
73 
74     }
75 
76 }

如果使用自定義使用者資訊表、角色資訊表、角色許可權表,例項程式碼,如下所示:

 1 package com.bie.realm;
 2 
 3 import com.alibaba.druid.pool.DruidDataSource;
 4 import org.apache.shiro.SecurityUtils;
 5 import org.apache.shiro.authc.UsernamePasswordToken;
 6 import org.apache.shiro.mgt.DefaultSecurityManager;
 7 import org.apache.shiro.realm.jdbc.JdbcRealm;
 8 import org.apache.shiro.subject.Subject;
 9 import org.junit.Test;
10 
11 /**
12  * @ProjectName: shiro
13  * @Package: com.bie.realm
14  * @ClassName: IniRealmTest
15  * @Author: biehl
16  * @Description: ${description}
17  * @Date: 2020/8/6 11:53
18  * @Version: 1.0
19  */
20 public class JdbcRealmTest {
21 
22     // 設定資料來源
23     DruidDataSource druidDataSource = new DruidDataSource();
24 
25     {
26         druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
27         druidDataSource.setUsername("root");
28         druidDataSource.setPassword("123456");
29     }
30 
31 
32     @Test
33     public void testAuthentication() {
34         // 設定JdbcRealm
35         JdbcRealm jdbcRealm = new JdbcRealm();
36         // 設定jdbc的資料來源
37         jdbcRealm.setDataSource(druidDataSource);
38         // 設定許可權的開關,預設是false,設定為true才可以查詢許可權資料的。
39         jdbcRealm.setPermissionsLookupEnabled(true);
40 
41         // 如果自定義資料表結構的時候
42         String userSql = "SELECT password from users_test WHERE name = ? ";
43         // 將認證的sql語句使用自己的sql語句
44         jdbcRealm.setAuthenticationQuery(userSql);
45 
46         // 使用者角色的自定義表
47         String userRoleSql = "select role_name from user_roles_test where name = ? ";
48         jdbcRealm.setUserRolesQuery(userRoleSql);
49 
50         // 角色許可權自定義表
51         String rolePermissionSql = "select permission from roles_permissions_test where name = ? ";
52         jdbcRealm.setPermissionsQuery(rolePermissionSql);
53 
54         // 1、認證第一步,構建SecurityManager環境
55         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
56         // 設定Realm
57         defaultSecurityManager.setRealm(jdbcRealm);
58 
59         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
60         // 設定SecurityManager環境
61         SecurityUtils.setSecurityManager(defaultSecurityManager);
62         Subject subject = SecurityUtils.getSubject();
63 
64         // 3、第三步,提交認證
65         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
66         subject.login(token);
67 
68 
69         // 4、第四步,Realm驗證
70         boolean authenticated = subject.isAuthenticated();
71         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
72 
73         // 5、檢查角色,檢查管理員的角色,給使用者admin配備角色admin
74         subject.checkRole("admin");
75         System.out.println("檢查管理員admin!");
76         subject.checkRoles("admin", "user");
77         System.out.println("檢查管理員admin、普通使用者角色user!");
78 
79         // 6、檢查許可權,檢查admin角色是否擁有使用者刪除的許可權
80         subject.checkPermission("user:delete");
81         System.out.println("檢查管理員擁有使用者刪除user:delete的許可權!");
82 
83         subject.checkPermission("user:update");
84         subject.checkPermission("user:select");
85         subject.checkPermission("user:insert");
86         System.out.println("檢查管理員擁有使用者刪除user:delete,user:update,user:select,user:insert的許可權!");
87 
88     }
89 
90 }

8.3、Shiro自定義Realm,如下所示:

  1 package com.bie.shiro;
  2 
  3 import com.alibaba.druid.util.StringUtils;
  4 import org.apache.shiro.authc.AuthenticationException;
  5 import org.apache.shiro.authc.AuthenticationInfo;
  6 import org.apache.shiro.authc.AuthenticationToken;
  7 import org.apache.shiro.authc.SimpleAuthenticationInfo;
  8 import org.apache.shiro.authz.AuthorizationInfo;
  9 import org.apache.shiro.authz.SimpleAuthorizationInfo;
 10 import org.apache.shiro.realm.AuthorizingRealm;
 11 import org.apache.shiro.subject.PrincipalCollection;
 12 
 13 import java.util.HashMap;
 14 import java.util.HashSet;
 15 import java.util.Map;
 16 import java.util.Set;
 17 
 18 /**
 19  * 自定義Realm
 20  *
 21  * @ProjectName: shiro
 22  * @Package: com.bie.shiro
 23  * @ClassName: CustomRealm
 24  * @Author: biehl
 25  * @Description: ${description}
 26  * @Date: 2020/8/6 14:58
 27  * @Version: 1.0
 28  */
 29 public class CustomRealm extends AuthorizingRealm {
 30 
 31     // 模擬資料表的登陸
 32     private Map<String, String> userMap = new HashMap<String, String>();
 33 
 34     {
 35         userMap.put("admin", "123456");
 36 
 37         // 設定RealName名稱
 38         super.setName("customRealm");
 39     }
 40 
 41     /**
 42      * 授權使用
 43      *
 44      * @param principals
 45      * @return
 46      */
 47     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
 48         // 1、第一步,從認證資訊中獲取到使用者資訊。
 49         String userName = (String) principals.getPrimaryPrincipal();
 50         // 2、第二步,從資料庫中或者快取中通過使用者姓名獲取到角色資訊
 51         Set<String> roles = getRolesByUserName(userName);
 52         // 3、第三步,從資料庫中或者快取中通過使用者姓名獲取到許可權資訊
 53         Set<String> permissions = getPermissionsByUserName(userName);
 54         // 4、第四步,將獲取到角色資訊和許可權資訊返回
 55         SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
 56         // 設定許可權
 57         simpleAuthorizationInfo.setStringPermissions(permissions);
 58         // 設定角色
 59         simpleAuthorizationInfo.setRoles(roles);
 60         return simpleAuthorizationInfo;
 61     }
 62 
 63     /**
 64      * 通過使用者名稱獲取到許可權資訊
 65      *
 66      * @param userName
 67      * @return
 68      */
 69     private Set<String> getPermissionsByUserName(String userName) {
 70         // 建立一個集合物件
 71         Set<String> sets = new HashSet<String>();
 72         // 設定許可權名稱
 73         sets.add("user:select");
 74         sets.add("user:insert");
 75         sets.add("user:delete");
 76         sets.add("user:update");
 77         return sets;
 78     }
 79 
 80     /**
 81      * 模擬通過使用者姓名獲取到角色資訊
 82      *
 83      * @param userName
 84      * @return
 85      */
 86     private Set<String> getRolesByUserName(String userName) {
 87         // 建立一個集合物件
 88         Set<String> sets = new HashSet<String>();
 89         // 設定角色名稱
 90         sets.add("admin");
 91         sets.add("user");
 92         return sets;
 93     }
 94 
 95     /**
 96      * 認證使用
 97      *
 98      * @param token 主體傳過來的認證資訊
 99      * @return
100      * @throws AuthenticationException
101      */
102     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
103         // 1、第一步,通過主體傳過來的認證資訊獲取使用者名稱
104         String username = (String) token.getPrincipal();
105         // 2、通過使用者名稱到資料庫中獲取憑證
106         String password = getPasswordByUserName(username);
107         // 判斷獲取到的密碼是否存在,不存在直接返回null
108         if (StringUtils.isEmpty(password)) {
109             return null;
110         }
111         // 如果物件存在
112         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("admin", password, "customRealm");
113         return authenticationInfo;
114     }
115 
116     /**
117      * 通過使用者姓名獲取到使用者的密碼
118      *
119      * @param username
120      * @return
121      */
122     private String getPasswordByUserName(String username) {
123         // 正常情況下,需要讀取資料庫,這裡進行模擬
124         return this.userMap.get(username);
125     }
126 
127 }

自定義Realm的單元測試,如下所示:

 1 package com.bie.shiro;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.UsernamePasswordToken;
 5 import org.apache.shiro.mgt.DefaultSecurityManager;
 6 import org.apache.shiro.subject.Subject;
 7 import org.junit.Test;
 8 
 9 /**
10  * @ProjectName: shiro
11  * @Package: com.bie.shiro
12  * @ClassName: CustomRealmTest
13  * @Author: biehl
14  * @Description: ${description}
15  * @Date: 2020/8/6 15:10
16  * @Version: 1.0
17  */
18 public class CustomRealmTest {
19 
20     @Test
21     public void testAuthentication() {
22         // 0、建立一個自定義Realm:CustomRealm
23         CustomRealm customRealm = new CustomRealm();
24 
25         // 1、認證第一步,構建SecurityManager環境
26         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
27         defaultSecurityManager.setRealm(customRealm);
28 
29         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
30         // 設定SecurityManager環境
31         SecurityUtils.setSecurityManager(defaultSecurityManager);
32         Subject subject = SecurityUtils.getSubject();
33 
34         // 3、第三步,提交認證
35         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
36         subject.login(token);
37 
38         // 4、第四步,Realm驗證
39         boolean authenticated = subject.isAuthenticated();
40         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
41 
42         // 5、檢查角色,檢查管理員的角色,給使用者admin配備角色admin
43         subject.checkRole("admin");
44         System.out.println("檢查管理員admin!");
45 
46         // 6、檢查許可權,檢查admin角色是否擁有使用者刪除的許可權
47         subject.checkPermission("user:delete");
48         System.out.println("檢查管理員擁有使用者刪除user:delete的許可權!");
49 
50         subject.checkPermission("user:update");
51         subject.checkPermission("user:select");
52         subject.checkPermission("user:insert");
53         System.out.println("檢查管理員擁有使用者刪除user:delete,user:update,user:select,user:insert的許可權!");
54     }
55 
56 }

9、Shiro加密,Shiro雜湊內建。

  1)、HashedCredentialsMatcher。
  2)、自定義Realm中使用雜湊。
  3)、鹽的使用,單純的加密並不能滿足加密的要求,還需要進行加鹽slat,讓密碼更加難以識破。

  1 package com.bie.shiro;
  2 
  3 import com.alibaba.druid.util.StringUtils;
  4 import org.apache.shiro.authc.AuthenticationException;
  5 import org.apache.shiro.authc.AuthenticationInfo;
  6 import org.apache.shiro.authc.AuthenticationToken;
  7 import org.apache.shiro.authc.SimpleAuthenticationInfo;
  8 import org.apache.shiro.authz.AuthorizationInfo;
  9 import org.apache.shiro.authz.SimpleAuthorizationInfo;
 10 import org.apache.shiro.crypto.hash.Md5Hash;
 11 import org.apache.shiro.realm.AuthorizingRealm;
 12 import org.apache.shiro.subject.PrincipalCollection;
 13 import org.apache.shiro.util.ByteSource;
 14 
 15 import java.util.HashMap;
 16 import java.util.HashSet;
 17 import java.util.Map;
 18 import java.util.Set;
 19 
 20 /**
 21  * 自定義Realm
 22  *
 23  * @ProjectName: shiro
 24  * @Package: com.bie.shiro
 25  * @ClassName: CustomRealm
 26  * @Author: biehl
 27  * @Description: ${description}
 28  * @Date: 2020/8/6 14:58
 29  * @Version: 1.0
 30  */
 31 public class CustomRealm extends AuthorizingRealm {
 32 
 33     // 模擬資料表的登陸
 34     private Map<String, String> userMap = new HashMap<String, String>();
 35 
 36     {
 37         // userMap.put("admin", "123456");
 38         userMap.put("admin", "496edd8064892864b76c5fd3a732544b");
 39 
 40         // 設定RealName名稱
 41         super.setName("customRealm");
 42     }
 43 
 44     /**
 45      * 授權使用
 46      *
 47      * @param principals
 48      * @return
 49      */
 50     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
 51         // 1、第一步,從認證資訊中獲取到使用者資訊。
 52         String userName = (String) principals.getPrimaryPrincipal();
 53         // 2、第二步,從資料庫中或者快取中通過使用者姓名獲取到角色資訊
 54         Set<String> roles = getRolesByUserName(userName);
 55         // 3、第三步,從資料庫中或者快取中通過使用者姓名獲取到許可權資訊
 56         Set<String> permissions = getPermissionsByUserName(userName);
 57         // 4、第四步,將獲取到角色資訊和許可權資訊返回
 58         SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
 59         // 設定許可權
 60         simpleAuthorizationInfo.setStringPermissions(permissions);
 61         // 設定角色
 62         simpleAuthorizationInfo.setRoles(roles);
 63         return simpleAuthorizationInfo;
 64     }
 65 
 66     /**
 67      * 通過使用者名稱獲取到許可權資訊
 68      *
 69      * @param userName
 70      * @return
 71      */
 72     private Set<String> getPermissionsByUserName(String userName) {
 73         // 建立一個集合物件
 74         Set<String> sets = new HashSet<String>();
 75         // 設定許可權名稱
 76         sets.add("user:select");
 77         sets.add("user:insert");
 78         sets.add("user:delete");
 79         sets.add("user:update");
 80         return sets;
 81     }
 82 
 83     /**
 84      * 模擬通過使用者姓名獲取到角色資訊
 85      *
 86      * @param userName
 87      * @return
 88      */
 89     private Set<String> getRolesByUserName(String userName) {
 90         // 建立一個集合物件
 91         Set<String> sets = new HashSet<String>();
 92         // 設定角色名稱
 93         sets.add("admin");
 94         sets.add("user");
 95         return sets;
 96     }
 97 
 98     /**
 99      * 認證使用
100      *
101      * @param token 主體傳過來的認證資訊
102      * @return
103      * @throws AuthenticationException
104      */
105     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
106         // 1、第一步,通過主體傳過來的認證資訊獲取使用者名稱
107         String username = (String) token.getPrincipal();
108         // 2、通過使用者名稱到資料庫中獲取憑證
109         // 如果使用了shiro的HashedCredentialsMatcher加密,那麼這裡儲存的是加密後的密文
110         String password = getPasswordByUserName(username);
111         // 判斷獲取到的密碼是否存在,不存在直接返回null
112         if (StringUtils.isEmpty(password)) {
113             return null;
114         }
115         // 如果物件存在
116         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("admin", password, "customRealm");
117 
118         // 如果加了鹽salt,認證返回的時候需要見鹽salt設定進去的
119         authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("654321"));
120         // 將加了鹽的認證使用者返回
121         return authenticationInfo;
122     }
123 
124     /**
125      * 通過使用者姓名獲取到使用者的密碼
126      *
127      * @param username
128      * @return
129      */
130     private String getPasswordByUserName(String username) {
131         // 正常情況下,需要讀取資料庫,這裡進行模擬
132         return this.userMap.get(username);
133     }
134 
135     public static void main(String[] args) {
136         // 加鹽salt讓密碼更加難以識破
137         Md5Hash md5Hash = new Md5Hash("123456","654321");
138         System.out.println(md5Hash);
139     }
140 
141 }

自定義Realm的單元測試,如下所示:

 1 package com.bie.shiro;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.UsernamePasswordToken;
 5 import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
 6 import org.apache.shiro.mgt.DefaultSecurityManager;
 7 import org.apache.shiro.subject.Subject;
 8 import org.junit.Test;
 9 
10 /**
11  * @ProjectName: shiro
12  * @Package: com.bie.shiro
13  * @ClassName: CustomRealmTest
14  * @Author: biehl
15  * @Description: ${description}
16  * @Date: 2020/8/6 15:10
17  * @Version: 1.0
18  */
19 public class CustomRealmTest {
20 
21     @Test
22     public void testAuthentication() {
23         // 0、建立一個自定義Realm:CustomRealm
24         CustomRealm customRealm = new CustomRealm();
25 
26         // shiro加密
27         HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
28         // 設定加密方式為md5
29         hashedCredentialsMatcher.setHashAlgorithmName("md5");
30         // 設定加密的次數
31         hashedCredentialsMatcher.setHashIterations(1);
32 
33         // 設定自定義Realm的HashedCredentialsMatcher物件
34         customRealm.setCredentialsMatcher(hashedCredentialsMatcher);
35 
36 
37         // 1、認證第一步,構建SecurityManager環境
38         DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
39         defaultSecurityManager.setRealm(customRealm);
40 
41         // 2、第二步,主體提交認證請求,使用SecurityUtils獲取到主體
42         // 設定SecurityManager環境
43         SecurityUtils.setSecurityManager(defaultSecurityManager);
44         Subject subject = SecurityUtils.getSubject();
45 
46         // 3、第三步,提交認證
47         UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
48         subject.login(token);
49 
50         // 4、第四步,Realm驗證
51         boolean authenticated = subject.isAuthenticated();
52         System.out.println("isAuthenticated是否進行了認證:" + authenticated);
53 
54         // 5、檢查角色,檢查管理員的角色,給使用者admin配備角色admin
55         subject.checkRole("admin");
56         System.out.println("檢查管理員admin!");
57 
58         // 6、檢查許可權,檢查admin角色是否擁有使用者刪除的許可權
59         subject.checkPermission("user:delete");
60         System.out.println("檢查管理員擁有使用者刪除user:delete的許可權!");
61 
62         subject.checkPermission("user:update");
63         subject.checkPermission("user:select");
64         subject.checkPermission("user:insert");
65         System.out.println("檢查管理員擁有使用者刪除user:delete,user:update,user:select,user:insert的許可權!");
66     }
67 
68 }