专栏首页别先生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 }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于jsp+servlet图书管理系统之后台用户信息修改操作

    上一篇的博客写的是查询操作,且附有源码和数据库,这篇博客写的是修改操作,附有从头至尾写的代码(详细的注释)和数据库!  此次修改操作的源码和数据库:http:...

    别先生
  • Shiro集成Spring

    1、Shiro集成Spring,使用maven进行jar包的依赖与管理,pom.xml的配置文件,如下所示:

    别先生
  • |ERROR|ERROR: missing data for column "createtime" (seg3 slice1 192.168.66.23:40001 pid=33370)之mys

    引发这个错误,并不是这个字段引起的错误,一般是这个字段临近的字段存在空格或者换行符引发的错误。

    别先生
  • 记一次access数据库SQL注入测试

    http://www.xxx.com/zxdt_detail.asp?id=1080 AND (SELECT top 1 len(username) FROM ...

    ittongluren
  • python测试开发django-19.admin后台自定义显示

    django的admin后台默认显示的内容很少,只显示了表的相关信息,查看字段内容需点开详情才能查看,不是很直观。 在admin.py文件里面是可以自定义相关的...

    上海-悠悠
  • C++核心准则​SL.io.3:优先使用iostream进行I / O

    iostreams are safe, flexible, and extensible.

    面向对象思考
  • 6.2 Spring Boot集成jpa6.2 Spring Boot集成jpa小结

    Java持久化API(JPA,Java Persistence API)是一个将对象映射为关系数据库的标准技术。JPA通过注解或XML描述ORM(Object ...

    一个会写诗的程序员
  • SpringBoot入门建站全系列(二十一)Mybatis使用乐观锁与悲观锁

    之前有两篇《SpringBoot入门建站全系列(三)Mybatis操作数据库》和《SpringBoot入门建站全系列(四)Mybatis使用进阶篇:动态SQL与...

    品茗IT
  • 一、初识jQuery

    1.x:兼容ie678,但相对其它版本文件较大,官方只做BUG维护,功能不再新增,最终版本:1.12.4 (2016年5月20日).

    Dreamy.TZK
  • Python采用并发查询mysql以及调用API灌数据 (八)- 异步并发加锁,保证数据安全

    上一篇文章已经编写了异步并发API请求灌数据,那么本章节我们来继续编写异步并发加锁,保证数据安全

    Devops海洋的渔夫

扫码关注云+社区

领取腾讯云代金券