前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shiro安全框架入门学习

Shiro安全框架入门学习

作者头像
别先生
发布2020-09-01 15:15:43
4370
发布2020-09-01 15:15:43
举报
文章被收录于专栏:别先生别先生

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如下所示:

代码语言:javascript
复制
 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>

认证的步骤,如下所示:

代码语言:javascript
复制
 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的授权过程,如下所示:

实现代码,如下所示:

代码语言:javascript
复制
 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配置文件来设置账号,设置角色和账号的绑定,设置权限等功能。

代码语言:javascript
复制
 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配置文件,如下所示:

代码语言:javascript
复制
1 [users]
2 admin=123456,admin
3 [roles]
4 admin=user:delete,user:update,user:select,user:insert

8.2、Shiro内置的JdbcRealm,如果使用默认的数据表结构,可以直接设置账号,设置角色和账号的绑定,设置权限等功能。

代码语言:javascript
复制
 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默认使用的数据表结构,这里新增了几条数据,如下所示:

代码语言:javascript
复制
 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的案例代码,如下所示:

代码语言:javascript
复制
 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 }

如果使用自定义用户信息表、角色信息表、角色权限表,实例代码,如下所示:

代码语言:javascript
复制
 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,如下所示:

代码语言:javascript
复制
  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的单元测试,如下所示:

代码语言:javascript
复制
 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,让密码更加难以识破。

代码语言:javascript
复制
  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的单元测试,如下所示:

代码语言:javascript
复制
 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 }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-08-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
访问管理
访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档