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 }