![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
什么是ACL和RBAC
ACL
- Access Control list:访问控制列表
- 优点:简单易用,开发便捷
- 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理
- 例子:常见的文件系统权限设计,直接给用户加权限
RBAC
- Role Based Access Control:基于角色的访问控制
- 权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
- 优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
- 缺点:开发比ACL相对复杂
- 例子:基于RBAC模型的权限验证框架,Apache Shiro
什么是Apache Shiro
官网地址
介绍
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
什么是身份认证
Authentication,身份认证,一般就是登陆校验
什么是授权
Authorization,给用户分配角色或者访问某些资源的权限
什么是会话管理
Session Management,用户的会话管理员,多数情况下是web session
什么是加密
Cryptography,数据加密,比如密码加解密
核心概念
Subject
我们把用户或者程序称为主体,主体去访问系统或者资源
SecurityManager
安全管理器,Subject的认证和授权都要在安全管理器下进行
Realm
数据域,Shiro和安全数据的连接器,通过realm获取认证授权相关信息
Authenticator
认证器,主要负责Subject的认证
Authorizer
授权器,主要负责Subject的授权,控制Subject拥有的角色或者权限
Crytography
加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的API
Cache Manager
缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能
快速上手
构建项目
认证和授权
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test; /**
* @Description:
* @Author:chenyanbin
* @Date:2020/12/27 7:43 下午
* @Versiion:1.0
*/
public class QuickStartTest {
private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
private SimpleAccountRealm accountRealm = new SimpleAccountRealm(); @Before
public void init() {
//初始化数据源,模拟从数据库中取的数据
accountRealm.addAccount("laochen", "123");
accountRealm.addAccount("laowang", "123456");
//构建环境
defaultSecurityManager.setRealm(accountRealm);
} @Test
public void testAuthentication() {
//设置上下文
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取当前主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laowang", "123456");
subject.login(usernamePasswordToken);
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
} }
QuickStartTest.java
常用API
//是否有对应的角色
subject.hasRole("root");
//获取subject名
subject.getPrincipal();
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断
subject.checkRole("admin");
//检查是否有对应的角色
subject.hasRole("admin");
//退出登录
subject.logout();
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test; /**
* @Description:
* @Author:chenyanbin
* @Date:2020/12/27 7:43 下午
* @Versiion:1.0
*/
public class QuickStartAPITest {
private DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
private SimpleAccountRealm accountRealm = new SimpleAccountRealm(); @Before
public void init() {
//初始化数据源,模拟从数据库中取的数据
accountRealm.addAccount("laochen", "123","root","admin");
accountRealm.addAccount("laowang", "123456","user");
//构建环境
defaultSecurityManager.setRealm(accountRealm);
} @Test
public void testAuthentication() {
//设置上下文
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取当前主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laochen", "123");
subject.login(usernamePasswordToken);
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
//是否有对应的角色
System.out.println("是否有对应的root角色:"+subject.hasRole("root"));
//获取subject名
System.out.println("获取subject名:"+subject.getPrincipal());
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断,没有的话,直接报错
subject.checkRole("admin");
//检查是否有对应的角色
System.out.println("是否存在admin角色:"+subject.hasRole("admin"));
//退出登录
subject.logout();
System.out.println("退出登录后,认证结果:" + authenticated);
} }
QuickStartAPITest.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ybchen</groupId>
<artifactId>springboot_shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_shiro</name>
<description>SpringBoot整合Shiro</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<!--Shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.0</version>
</dependency> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
pom.xml
realm实战
作用
Shiro从Realm获取安全数据
概念
- principal:主体的标识,可以有多个,但是需要具有唯一性,如:手机号、邮箱
- credential:凭证,一般就是密码
内置ini realm
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Before;
import org.junit.Test; /**
* @Description:从ini配置文件中读取用户与角色
* @Author:chenyanbin
* @Date:2020/12/27 8:52 下午
* @Versiion:1.0
*/
public class QuickStartIniTest {
@Before
public void init() { } @Test
public void testAuthentication() {
//创建SecurityManager工厂,通过配置文件ini创建
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager=factory.getInstance();
//将securityManager设置到当前运行环境中
SecurityUtils.setSecurityManager(securityManager);
//获取主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laochen", "123");
subject.login(usernamePasswordToken);
//判断是否成功
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
//是否有对应的角色
System.out.println("是否有对应的root角色:"+subject.hasRole("root"));
//获取subject名
System.out.println("获取subject名:"+subject.getPrincipal());
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断,没有的话,直接报错
subject.checkRole("admin");
//检查是否有对应的角色
System.out.println("是否存在admin角色:"+subject.hasRole("admin"));
//退出登录
subject.logout();
System.out.println("退出登录后,认证结果:" + authenticated);
}
}
QuickStartIniTest.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
# 格式 name=password,role1,role2,..roleN
[users]
# 账户=laochen;密码=123;角色=admin
laochen = 123, admin
laowang = 456, user # 格式 role=permission1,permission2...permissionN 也可以用通配符
# 下面配置user的权限为所有video:find,video:buy,如果需要配置video全部操作crud 则 user = video:*
[roles]
user = video:find,video:buy
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
shiro.ini
校验权限
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Before;
import org.junit.Test; /**
* @Description:从ini配置文件中读取用户与角色
* @Author:chenyanbin
* @Date:2020/12/27 8:52 下午
* @Versiion:1.0
*/
public class QuickStartIniTest {
@Before
public void init() { } @Test
public void testAuthentication() {
//创建SecurityManager工厂,通过配置文件ini创建
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager=factory.getInstance();
//将securityManager设置到当前运行环境中
SecurityUtils.setSecurityManager(securityManager);
//获取主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laochen", "123");
subject.login(usernamePasswordToken);
//判断是否成功
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
//是否有对应的角色
System.out.println("是否有对应的root角色:"+subject.hasRole("root"));
//获取subject名
System.out.println("获取subject名:"+subject.getPrincipal());
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断,没有的话,直接报错
subject.checkRole("admin");
//检查是否有对应的角色
System.out.println("是否存在admin角色:"+subject.hasRole("admin"));
//================权限,没有的话直接报错================
subject.checkPermission("video:delete");
System.out.println("是否有video:delete权限:"+subject.isPermitted("video:delete"));
//退出登录
subject.logout();
System.out.println("退出登录后,认证结果:" + subject.isAuthenticated());
}
}
QuickStartIniTest.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
# 格式 name=password,role1,role2,..roleN
[users]
# 账户=laochen;密码=123;角色=admin
laochen = 123, admin
laowang = 456, user # 格式 role=permission1,permission2...permissionN 也可以用通配符
# 下面配置user的权限为所有video:find,video:buy,如果需要配置video全部操作crud 则 user = video:*
[roles]
user = video:find,video:buy
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
shiro.ini
注:配置文件必须ini结尾
内置JdbcRealm
方式一
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test; /**
* @Description:
* @Author:chenyanbin
* @Date:2020/12/27 10:40 下午
* @Versiion:1.0
*/
public class QuickStartJdbcIniTest {
@Test
public void testAuthentication(){
//创建SecurityManager工厂,通过配置文件ini创建
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
SecurityManager securityManager=factory.getInstance();
//将securityManager设置到当前运行环境中
SecurityUtils.setSecurityManager(securityManager);
//获取主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laochen", "123");
subject.login(usernamePasswordToken);
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
//是否有对应的角色
System.out.println("是否有对应的root角色:"+subject.hasRole("root"));
//获取subject名
System.out.println("获取subject名:"+subject.getPrincipal());
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断,没有的话,直接报错
subject.checkRole("role1");
//检查是否有对应的角色
System.out.println("是否存在role1角色:"+subject.hasRole("role1"));
//================权限,没有的话直接报错================
//subject.checkPermission("video:delete");
System.out.println("是否有video:buy权限:"+subject.isPermitted("video:buy"));
//退出登录
subject.logout();
System.out.println("退出登录后,认证结果:" + subject.isAuthenticated());
}
}
QuickStartJdbcIniTest.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
#声明Realm,指定realm类型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#配置数据源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource=com.alibaba.druid.pool.DruidDataSource
# mysql-connector-java 5 用的驱动url是com.mysql.jdbc.Driver,mysql-connector-java6以后用的是com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver
#避免安全警告
dataSource.url=jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
#账号、密码
dataSource.username=root
dataSource.password=root
#指定数据源
jdbcRealm.dataSource=$dataSource
#开启查找权限, 默认是false
jdbcRealm.permissionsLookupEnabled=true
#指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开
securityManager.realms=$jdbcRealm
jdbcrealm.ini
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
/*
Navicat Premium Data Transfer Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50731
Source Host : localhost:3306
Source Schema : shiro Target Server Type : MySQL
Target Server Version : 50731
File Encoding : 65001 Date: 27/12/2020 23:06:45
*/ SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for roles_permissions
-- ----------------------------
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_name` varchar(100) DEFAULT NULL COMMENT '角色名',
`permission` varchar(100) DEFAULT NULL COMMENT '权限名',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_roles_permissions` (`role_name`,`permission`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of roles_permissions
-- ----------------------------
BEGIN;
INSERT INTO `roles_permissions` VALUES (4, 'admin', 'video:*');
INSERT INTO `roles_permissions` VALUES (3, 'role1', 'video:buy');
INSERT INTO `roles_permissions` VALUES (2, 'role1', 'video:find');
INSERT INTO `roles_permissions` VALUES (5, 'role2', '*');
INSERT INTO `roles_permissions` VALUES (1, 'root', '*');
COMMIT; -- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`role_name` varchar(100) DEFAULT NULL COMMENT '角色名',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_roles` (`username`,`role_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of user_roles
-- ----------------------------
BEGIN;
INSERT INTO `user_roles` VALUES (1, 'laochen', 'role1');
INSERT INTO `user_roles` VALUES (2, 'laochen', 'role3');
INSERT INTO `user_roles` VALUES (4, 'laowang', 'admin');
INSERT INTO `user_roles` VALUES (3, 'laowang', 'root');
COMMIT; -- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`password_salt` varchar(100) DEFAULT NULL COMMENT '密码加盐规则',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_users_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of users
-- ----------------------------
BEGIN;
INSERT INTO `users` VALUES (1, 'laochen', '123', NULL);
INSERT INTO `users` VALUES (2, 'laowang', '456', NULL);
COMMIT; SET FOREIGN_KEY_CHECKS = 1;
建表语句.sql
注意
表名和字段要对应上,否则自定义定,继承:AuthorizingRealm,重写sql查询语句!!!!并重新指定realm类型!!!!
方式二
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test; /**
* @Description:
* @Author:chenyanbin
* @Date:2020/12/27 10:40 下午
* @Versiion:1.0
*/
public class QuickStartJdbc2Test {
@Test
public void testAuthentication() {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
ds.setUsername("root");
ds.setPassword("root");
JdbcRealm jdbcRealm = new JdbcRealm();
//开启查找权限, 默认是false
jdbcRealm.setPermissionsLookupEnabled(true);
//配置数据源
jdbcRealm.setDataSource(ds);
//jdbc与DefaultSecurityManager关联
securityManager.setRealm(jdbcRealm);
//=======================下面内容相同==============================
//将securityManager设置到当前运行环境中
SecurityUtils.setSecurityManager(securityManager);
//获取主体
Subject subject = SecurityUtils.getSubject();
//模拟用户登录,账户、密码
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("laochen", "123");
subject.login(usernamePasswordToken);
//判断是否成功
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:" + authenticated);
//是否有对应的角色
System.out.println("是否有对应的root角色:" + subject.hasRole("root"));
//获取subject名
System.out.println("获取subject名:" + subject.getPrincipal());
//检查是否有对应的角色,无返回值,直接在SecurityManager里面进行判断,没有的话,直接报错
subject.checkRole("role1");
//检查是否有对应的角色
System.out.println("是否存在role1角色:" + subject.hasRole("role1"));
//================权限,没有的话直接报错================
//subject.checkPermission("video:delete");
System.out.println("是否有video:buy权限:" + subject.isPermitted("video:buy"));
//退出登录
subject.logout();
System.out.println("退出登录后,认证结果:" + subject.isAuthenticated());
}
}
QuickStartJdbc2Test.java
自定义realm
继承AuthorizingRealm,重写授权方法doGetAuthorizationInfo、重写认证方法doGetAuthenticationInfo。
UsernamePasswordToken:对应就是shiro的token中有Principal和Credential。
SimpleAuthorizationInfo:代表用户角色权限信息
SimpleAuthenticationInfo:代表该用户的认证信息
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set; /**
* @Description:自定义Realm
* @Author:chenyanbin
* @Date:2020/12/28 8:41 下午
* @Versiion:1.0
*/
public class CustomRealm extends AuthorizingRealm {
private final Map<String, String> userInfoMap = new HashMap<>();
//role-->permission
private final Map<String, Set<String>> permissionMap = new HashMap<>();
//user-->role
private final Map<String, Set<String>> roleMap = new HashMap<>(); /**
* 代码块初始化数据
*/
{
userInfoMap.put("laochen", "123");
userInfoMap.put("laowang", "456");
//================================
Set<String> set1 = new HashSet<>();
set1.add("video:find");
set1.add("video:buy");
Set<String> set2 = new HashSet<>();
set2.add("video:add");
set2.add("video:delete");
permissionMap.put("laochen", set1);
permissionMap.put("laowang", set2);
//================================
Set<String> set3 = new HashSet<>();
Set<String> set4 = new HashSet<>();
set3.add("role1");
set3.add("role2");
set4.add("root");
roleMap.put("laochen", set3);
roleMap.put("laowang", set4);
} /**
* 授权认证
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权 AuthorizationInfo");
String name = (String) principals.getPrimaryPrincipal();
//权限
Set<String> permissions = getPermissionsByNameFromDB(name);
//角色
Set<String> roles = getRoleByNameFromDB(name);
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setRoles(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
} /**
* 模拟从数据库中取角色
*
* @param name
* @return
*/
private Set<String> getRoleByNameFromDB(String name) {
return roleMap.get(name);
} /**
* 模拟从数据库中取权限
*
* @param name
* @return
*/
private Set<String> getPermissionsByNameFromDB(String name) {
return permissionMap.get(name);
} /**
* 登录认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证 doGetAuthenticationInfo");
//用户名
String name = (String) token.getPrincipal();
//从DB中根据用户取密码
String pwd = getPwdByUserNameFromDB(name);
if (pwd == null || "".equals(pwd)) {
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, pwd, this.getName());
return simpleAuthenticationInfo;
} /**
* 模拟从数据库中取密码
*
* @param name
* @return
*/
private String getPwdByUserNameFromDB(String name) {
return userInfoMap.get(name);
}
}
CustomRealm.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test; /**
* @Description:自定义realm
* @Author:chenyanbin
* @Date:2020/12/28 8:43 下午
* @Versiion:1.0
*/
public class QuickCustomRealmTest {
private CustomRealm customRealm=new CustomRealm();
private DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager(); @Before
public void init() {
//构建环境
defaultSecurityManager.setRealm(customRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
} @Test
public void testAuthentication(){
//获取当前操作的主体
Subject subject = SecurityUtils.getSubject();
//用户输入账号、密码
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("laochen","123");
subject.login(usernamePasswordToken);
System.out.println("认证结果:"+subject.isAuthenticated());
//拿到主体标识属性
System.out.println("获取subject名:"+subject.getPrincipal());
//是否有role1角色,没有则报错
subject.checkRole("role1");
//是否有对应的角色
System.out.println("是否有对应的角色:"+subject.hasRole("role1"));
//是否有对应的权限
System.out.println("是否有对应的权限:"+subject.isPermitted("video:find"));
}
}
QuickCustomRealmTest.java
Filter过滤器
- 核心过滤器
- DefaultFilter,配置那个路径对应那个拦截器进行处理
- authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter
- 需要认证登录才能访问
- user:org.apache.shiro.web.filter.authc.UseerrFilter
- 用户拦截器,表示必须存在用户
- anon:org.apache.shiro.web.filter.authc.AnonymoousFilter
- 匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源。
- roles:org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
- 角色授权拦截器,验证用户是否拥有角色
- 参数可写多个,表示某些角色才能通过,多个参数时,写roles["root,role1"],当有多个参数时必须每个参数都通过才算通过
- perms:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
- 权限授权拦截器,验证用户是否拥有权限
- 参数可写多个,表示需要某些权限才能通过,多个参数写perms["user,admin"],当有多个参数时必须每个参数都通过才算可以
- authcBasci:org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
- httpBasic,身份验证拦截器
- logout:org.apache.shiro.web.filter.authc.LogoutFilter
- 退出拦截器,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(),设置的url
- port:org.apache.shiro.web.filter.authz.PortFilter
- 端口拦截器,可通过的端口
- ssl:org.apache.shiro.web.filter.authz.SslFilter
- ssl拦截器,只有请求协议是https才能通过
Filter配置路径
- 路径通配符支持?、*、**,注意通配符匹配不包含目录分隔符“/”
- *:可以匹配所有,不加*,可以进行前缀匹配,但多个冒号就需要多个*来匹配
url权限采取第一次匹配优先的方式
?:匹配一个字符,如:/user?,匹配:/user1,但不匹配:/user/
*:匹配零个或多个字符串,如:/add*,匹配:/addtest,但不匹配:/user/1
**:匹配路径中的零个或多个路径,如:/user/**将匹配:/user/xxx/yyy
Shiro权限控制注解
注解方式
- @RequiresRoles(value={"admin","editor"},logical=Logical.AND)
- 需要角色:admin和editor两个角色,AND表示两个同时成立
- RequiresPermissions(value={"user:add","user:del"},logical.OR)
- 需要权限user:add或user:del权限其中一个,OR是或的意思
- @RequiresAuthentication
- 已经授过权,调用Subject.isAuthenticated()返回true
- @RequiresUser
- 身份验证或通过记住我登录过的
使用文件的方式
使用ShiroConfig。
编程方式
SpringBoot整合Shiro
技术栈
前后端分离+SpringBoot+Mysql+Mybatis+Shiro+Redis+JDK8
数据库表
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
/*
Navicat Premium Data Transfer Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50731
Source Host : localhost:3306
Source Schema : shiro_2 Target Server Type : MySQL
Target Server Version : 50731
File Encoding : 65001 Date: 03/01/2021 22:36:28
*/ SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) DEFAULT NULL COMMENT '权限名称',
`url` varchar(255) DEFAULT NULL COMMENT '路径',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='权限'; -- ----------------------------
-- Records of permission
-- ----------------------------
BEGIN;
INSERT INTO `permission` VALUES (1, 'video_update', '/api/video/update');
INSERT INTO `permission` VALUES (2, 'video_delete', '/api/video/delete');
INSERT INTO `permission` VALUES (3, 'video_add', '/api/video/add');
INSERT INTO `permission` VALUES (4, 'order_list', '/api/order/list');
INSERT INTO `permission` VALUES (5, 'user_list', '/api/user/list');
COMMIT; -- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) DEFAULT NULL COMMENT '角色名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='角色'; -- ----------------------------
-- Records of role
-- ----------------------------
BEGIN;
INSERT INTO `role` VALUES (1, 'admin', '系统管理员');
INSERT INTO `role` VALUES (2, 'root', '超级管理员');
INSERT INTO `role` VALUES (3, 'user', '普通用户');
COMMIT; -- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_id` int(11) DEFAULT NULL COMMENT '角色id',
`permission_id` int(11) DEFAULT NULL COMMENT '权限id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='角色-权限'; -- ----------------------------
-- Records of role_permission
-- ----------------------------
BEGIN;
INSERT INTO `role_permission` VALUES (1, 1, 1);
INSERT INTO `role_permission` VALUES (2, 1, 2);
INSERT INTO `role_permission` VALUES (3, 2, 1);
INSERT INTO `role_permission` VALUES (4, 2, 2);
INSERT INTO `role_permission` VALUES (5, 2, 3);
INSERT INTO `role_permission` VALUES (6, 2, 4);
INSERT INTO `role_permission` VALUES (7, 2, 5);
INSERT INTO `role_permission` VALUES (8, 3, 5);
COMMIT; -- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`salt` varchar(255) DEFAULT NULL COMMENT '加盐',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户'; -- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'laochen', '123', NULL, NULL);
INSERT INTO `user` VALUES (2, 'laowang', '456', NULL, NULL);
INSERT INTO `user` VALUES (3, 'laoli', '789', NULL, NULL);
COMMIT; -- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_id` int(11) DEFAULT NULL COMMENT '角色id',
`user_id` int(11) DEFAULT NULL COMMENT '用户id',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='角色-用户关联表'; -- ----------------------------
-- Records of user_role
-- ----------------------------
BEGIN;
INSERT INTO `user_role` VALUES (1, 1, 1, 'laochen是系统管理员');
INSERT INTO `user_role` VALUES (2, 2, 2, 'laowang是超级管理员');
INSERT INTO `user_role` VALUES (3, 3, 3, 'laoli是普通用户');
INSERT INTO `user_role` VALUES (4, 1, 2, 'laowang是系统管理员');
COMMIT; SET FOREIGN_KEY_CHECKS = 1;
shiro_2.sql
项目结构
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.config; import com.ybchen.springboot_shiro.domain.Role;
import com.ybchen.springboot_shiro.domain.User;
import com.ybchen.springboot_shiro.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors; /**
* @Description:自定义realm
* @Author:chenyanbin
* @Date:2021/1/2 11:16 下午
* @Versiion:1.0
*/
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService; /**
* 进行权限校验的时候会调用
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("CustomRealm doGetAuthorizationInfo 授权");
//获取用户名
String userName = (String) principals.getPrimaryPrincipal();
User user = userService.findAllUserInfoByUserName(userName);
if (user == null) {
return null;
}
//角色集合
List<String> stringRoleList = new ArrayList<>();
//权限集合
List<String> stringPermissionList = new ArrayList<>();
List<Role> roleList = user.getRoleList();
stringRoleList = roleList.stream().map(
obj -> {
stringPermissionList.addAll(obj.getPermissionList()
.stream()
.map(per ->
per.getName()).collect(Collectors.toList()));
return obj.getName();
}).collect(Collectors.toList());
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addRoles(stringRoleList);
simpleAuthorizationInfo.addStringPermissions(stringPermissionList);
return simpleAuthorizationInfo;
} /**
* 用户登录的时候会调用
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("CustomRealm doGetAuthenticationInfo 认证");
//从token中获取用户信息
String uesrName = (String) token.getPrincipal();
User user = userService.findAllUserInfoByUserName(uesrName);
if (user == null) {
return null;
}
//密码
String pwd = user.getPassword();
if (pwd == null || "".equals(pwd)) {
return null;
}
return new SimpleAuthenticationInfo(uesrName, pwd, this.getClass().getName());
}
}
CustomRealm.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.config; import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable; /**
* @Description:自定义SessionManager
* @Author:chenyanbin
* @Date:2021/1/3 4:54 下午
* @Versiion:1.0
*/
public class CustomSessionManager extends DefaultWebSessionManager {
public static final String AUTHORIZATION="token"; public CustomSessionManager() {
super();
} @Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//获取sessionId
String sessionId= WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if (sessionId!=null){
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sessionId;
}else {
return super.getSessionId(request,response);
}
}
}
CustomSessionManager.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.config; import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap;
import java.util.Map; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 4:12 下午
* @Versiion:1.0
*/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
System.out.println("ShiroConfig ShiroFilterFactoryBean 执行");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//如果访问需要登录的某个接口,却没有登录,则调用此接口(如果不是前后端分离,则跳转页面)
shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
//shiroFilterFactoryBean.setLoginUrl("/xxx.jsp");
//登录成功后,跳转的链接,若前后端分离,没必要设置这个
//shiroFilterFactoryBean.setSuccessUrl("");
//登录成功,未授权会调用此方法
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit");
//拦截路径,必须使用:LinkedHashMap,要不然拦截效果会时有时无,因为使用的是无序的Map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//key=正则表达式路径,value=org.apache.shiro.web.filter.mgt.DefaultFilter
//退出过滤器
filterChainDefinitionMap.put("/logout", "logout");
//匿名可以访问,游客模式
filterChainDefinitionMap.put("/pub/**", "anon");
//登录用户才可以访问
filterChainDefinitionMap.put("/authc/**", "authc");
//管理员角色才能访问
filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//有编辑权限才能访问
filterChainDefinitionMap.put("/video/update", "perms[video_update]");
//authc:url必须通过认证才可以访问
//anon:url可以匿名访问
//过滤链是顺序执行,从上而下,一般把/**,放到最下面
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
} @Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//如果不是前后端分离,不用设置setSessionManager
securityManager.setSessionManager(sessionManager());
securityManager.setRealm(customRealm());
return securityManager;
} /**
* 自定义realm
*
* @return
*/
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
//因为数据库密码存的是明文,所以无需使用双重md5校验
// customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
} /**
* 密码验证器,双重md5
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//设置散列算法,使用md5算法
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列次数,使用2次md5算法,相当于md5(md5(xxx))
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
} /**
* 自定义SessionManager
*
* @return
*/
@Bean
public SessionManager sessionManager() {
CustomSessionManager customSessionManager = new CustomSessionManager();
//超时时间,默认 30分钟,会话超时,单位毫秒
// customSessionManager.setGlobalSessionTimeout(200000);
return customSessionManager;
}
}
ShiroConfig.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import com.ybchen.springboot_shiro.utils.JsonData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.Arrays;
import java.util.List; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 7:22 下午
* @Versiion:1.0
*/
@RestController
@RequestMapping("admin")
public class AdminController {
@GetMapping("/video/video_list")
public JsonData videoList() {
List<String> list = Arrays.asList("docker", "k8s", "jenkins");
return JsonData.buildSuccess(list);
}
}
AdminController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import org.springframework.web.bind.annotation.RestController; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 10:01 下午
* @Versiion:1.0
*/
@RestController
public class LogoutController {
// /**
// * 退出,没必要能这个,退出时,前端直接将token清空即可
// * 还需要获取前端传来的token,然后从shiro从清空指定的session_id
// * @return
// */
// @GetMapping("logout")
// public JsonData logout(){
// Subject subject= SecurityUtils.getSubject();
// subject.logout();
// return JsonData.buildSuccess("退出成功");
// }
}
LogoutController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import com.ybchen.springboot_shiro.utils.JsonData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.HashMap;
import java.util.Map; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 6:28 下午
* @Versiion:1.0
*/
@RestController
@RequestMapping("authc")
public class OrderController {
/**
* 购买记录
* @return
*/
@GetMapping("/video/play_record")
public JsonData findMyPlayRecord(){
Map<String,String> recordMap=new HashMap<>();
recordMap.put("1","SpringBoot");
recordMap.put("2","SpringMvc");
return JsonData.buildSuccess(recordMap);
}
}
OrderController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import com.ybchen.springboot_shiro.utils.JsonData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 9:20 下午
* @Versiion:1.0
*/
@RestController
public class OtherController {
@GetMapping("a")
public JsonData a(){
return JsonData.buildSuccess("ok");
}
}
OtherController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import com.ybchen.springboot_shiro.domain.UserQuery;
import com.ybchen.springboot_shiro.utils.JsonData;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 1:12 上午
* @Versiion:1.0
*/
@RestController
@RequestMapping("pub")
public class PublicController {
/**
* 需要登录
*
* @return
*/
@GetMapping("need_login")
public JsonData needLogin() {
return JsonData.buildSuccess(-1, "温馨提示:请使用对应的账号登录");
} /**
* 没权限
*
* @return
*/
@GetMapping("not_permit")
public JsonData notPermit() {
return JsonData.buildSuccess(-1, "温馨提示:拒绝访问,没权限");
} /**
* 首页
*
* @return
*/
@GetMapping("index")
public JsonData index() {
List<String> list = Arrays.asList("SpringBoot", "SpringMvc", "Mysql", "Redis");
return JsonData.buildSuccess(list);
} /**
* 登录接口
*
* @param userQuery
* @param request
* @param response
* @return
*/
@PostMapping("login")
public JsonData login(@RequestBody UserQuery userQuery, HttpServletRequest request, HttpServletResponse response) {
//拿到主体
Subject subject = SecurityUtils.getSubject();
try {
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userQuery.getUserName(), userQuery.getPassword());
subject.login(usernamePasswordToken);
Map<String,Object> info=new HashMap<>();
info.put("msg","登录成功");
info.put("session_id",subject.getSession().getId());
return JsonData.buildSuccess(info);
}catch (Exception e){
e.printStackTrace();
return JsonData.buildError("账号或密码错误");
}
}
}
PublicController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.controller; import com.ybchen.springboot_shiro.utils.JsonData;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 9:41 下午
* @Versiion:1.0
*/
@RestController
@RequestMapping("video")
public class VideoController {
@GetMapping("update")
public JsonData updateVideo() {
return JsonData.buildSuccess("更新成功");
}
@GetMapping("add")
public JsonData add(){
return JsonData.buildSuccess("添加成功");
}
}
VideoController.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.dao; import com.ybchen.springboot_shiro.domain.Permission;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import java.util.List; /**
* 权限
*/
public interface PermissionMapper {
/**
* 根据roleId查询所有权限
* @param roleId
* @return
*/
@Select("select p.id id,p.name name,p.url url from role_permission rp " +
"left join permission p on rp.permission_id=p.id " +
"where rp.role_id=#{roleId}")
List<Permission> findByPermissionListByRoleId(@Param("roleId") int roleId);
}
PermissionMapper.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.dao; import com.ybchen.springboot_shiro.domain.Role;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType; import java.util.List; /**
* 角色
*/
public interface RoleMapper {
/**
* 根据用户查询所有的角色
*
* @param userId 用户id
* @return
*/
@Select("select r.id id,r.name name,r.description description from user_role ur " +
"left join role r on ur.role_id=r.id " +
"where ur.user_id=#{userId}")
@Results(
value = {
@Result(id = true, property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "description", column = "description"),
@Result(property = "permissionList", column = "id",
many = @Many(select = "com.ybchen.springboot_shiro.dao.PermissionMapper.findByPermissionListByRoleId",
fetchType = FetchType.DEFAULT))
}
)
List<Role> findRoleListByUserId(@Param("userId") int userId);
}
RoleMapper.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.dao; import com.ybchen.springboot_shiro.domain.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; /**
* 用户
*/
public interface UserMapper {
/**
* 根据用户名查询用户
*
* @param userName 用户名
* @return
*/
@Select("select * from user where username=#{userName}")
User findByUserName(@Param("userName") String userName); /**
* 根据主键查询用户
*
* @param id 主键
* @return
*/
@Select("select * from user where id=#{userId}")
User findById(@Param("userId") int id); /**
* 根据用户名和密码查询用户
*
* @param userName 用户名
* @param password 密码
* @return
*/
@Select("select * from user where userName=#{userName} and password=#{password}")
User findByUserNameAndPassword(@Param("userName") String userName, @Param("password") String password);
}
UserMapper.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; /**
* @Description:权限
* @Author:chenyanbin
* @Date:2021/1/2 11:47 下午
* @Versiion:1.0
*/
public class Permission {
/**
* 主键
*/
private int id;
/**
* 权限名称
*/
private String name;
/**
* 路径
*/
private String url; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} @Override
public String toString() {
return "Permission{" +
"id=" + id +
", name='" + name + '\'' +
", url='" + url + '\'' +
'}';
}
}
Permission.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; import java.util.ArrayList;
import java.util.List; /**
* @Description:角色
* @Author:chenyanbin
* @Date:2021/1/2 11:43 下午
* @Versiion:1.0
*/
public class Role {
/**
* 主键
*/
private int id;
/**
* 角色名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 权限集合
*/
private List<Permission> permissionList=new ArrayList<>(); public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public List<Permission> getPermissionList() {
return permissionList;
} public void setPermissionList(List<Permission> permissionList) {
this.permissionList = permissionList;
} }
Role.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; /**
* @Description:角色权限
* @Author:chenyanbin
* @Date:2021/1/2 11:44 下午
* @Versiion:1.0
*/
public class RolePermission {
/**
* 主键
*/
private int id;
/**
* 角色id
*/
private int roleId;
/**
* 权限id
*/
private int permissiionId; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public int getRoleId() {
return roleId;
} public void setRoleId(int roleId) {
this.roleId = roleId;
} public int getPermissiionId() {
return permissiionId;
} public void setPermissiionId(int permissiionId) {
this.permissiionId = permissiionId;
} @Override
public String toString() {
return "RolePermission{" +
"id=" + id +
", roleId=" + roleId +
", permissiionId=" + permissiionId +
'}';
}
}
RolePermission.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; import java.util.ArrayList;
import java.util.Date;
import java.util.List; /**
* @Description:用户表
* @Author:chenyanbin
* @Date:2021/1/2 11:41 下午
* @Versiion:1.0
*/
public class User {
/**
* 主键
*/
private int id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 创建时间
*/
private Date createTime;
/**
* 密码加盐
*/
private String salt;
/**
* 角色集合
*/
private List<Role> roleList=new ArrayList<>(); public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public String getSalt() {
return salt;
} public void setSalt(String salt) {
this.salt = salt;
} public List<Role> getRoleList() {
return roleList;
} public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", createTime=" + createTime +
", salt='" + salt + '\'' +
", roleList=" + roleList +
'}';
}
}
User.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; import java.io.Serializable; /**
* @Description:接收用户名和密码
* @Author:chenyanbin
* @Date:2021/1/3 6:19 下午
* @Versiion:1.0
*/
public class UserQuery implements Serializable {
private String userName;
private String password; public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} @Override
public String toString() {
return "UserQuery{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
UserQuery.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.domain; /**
* @Description:用户角色
* @Author:chenyanbin
* @Date:2021/1/2 11:46 下午
* @Versiion:1.0
*/
public class UserRole {
/**
* 主键
*/
private int id;
/**
* 角色id
*/
private int roleId;
/**
* 用户id
*/
private int userId;
/**
* 备注
*/
private String remark; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public int getRoleId() {
return roleId;
} public void setRoleId(int roleId) {
this.roleId = roleId;
} public int getUserId() {
return userId;
} public void setUserId(int userId) {
this.userId = userId;
} public String getRemark() {
return remark;
} public void setRemark(String remark) {
this.remark = remark;
} @Override
public String toString() {
return "UserRole{" +
"id=" + id +
", roleId=" + roleId +
", userId=" + userId +
", remark='" + remark + '\'' +
'}';
}
}
UserRole.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.exception; /**
* @Description:自定义异常
* @Author:chenyanbin
* @Date:2021/1/3 7:31 下午
* @Versiion:1.0
*/
public class CustomException extends RuntimeException{
private Integer code;
private String msg; public CustomException(Integer code, String msg) {
this.code = code;
this.msg = msg;
} public Integer getCode() {
return code;
} public void setCode(Integer code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} @Override
public String toString() {
return "CustomException{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
}
CustomException.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.exception; import com.ybchen.springboot_shiro.utils.JsonData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; /**
* @ClassName:GlobalExceptiions
* @Description:TODO
* @Author:chenyb
* @Date:2020/12/9 11:34 上午
* @Versiion:1.0
*/
@ControllerAdvice
public class GlobalExceptiions {
private final Logger logger = LoggerFactory.getLogger(getClass()); @ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonData handle(Exception ex) {
logger.info("[ 全局异常 ] ===============》 {}", ex);
if (ex instanceof CustomException) {
CustomException customException = (CustomException) ex;
return JsonData.buildError(customException.getCode(), customException.getMsg());
}
return JsonData.buildError("系统内部错误,请联系管理员!");
}
}
GlobalExceptiions.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.service.impl; import com.ybchen.springboot_shiro.dao.RoleMapper;
import com.ybchen.springboot_shiro.dao.UserMapper;
import com.ybchen.springboot_shiro.domain.Role;
import com.ybchen.springboot_shiro.domain.User;
import com.ybchen.springboot_shiro.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.List; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 1:15 上午
* @Versiion:1.0
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper; @Override
public User findAllUserInfoByUserName(String userName) {
User user = userMapper.findByUserName(userName);
//用户角色的集合
List<Role> roleList = roleMapper.findRoleListByUserId(user.getId());
user.setRoleList(roleList);
return user;
} @Override
public User findSimpleUserInfoById(int userId) {
return userMapper.findById(userId);
} @Override
public User findSimpleUserInfoByUserName(String userName) {
return userMapper.findByUserName(userName);
}
}
UserServiceImpl.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.service; import com.ybchen.springboot_shiro.domain.User; public interface UserService {
/**
* 获取全部用户信息,包括角色、权限
* @param userName
* @return
*/
User findAllUserInfoByUserName(String userName); /**
* 获取用户基本信息
* @param userId
* @return
*/
User findSimpleUserInfoById(int userId); /**
* 根据用户名查询用户信息
* @param userName
* @return
*/
User findSimpleUserInfoByUserName(String userName);
}
UserService.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.utils; import java.io.Serializable; public class JsonData implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 状态码,0表示成功过,1表示处理中,-1表示失败
*/
private Integer code;
/**
* 业务数据
*/
private Object data;
/**
* 信息描述
*/
private String msg; public JsonData() {
} public JsonData(Integer code, Object data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
} /**
* 成功,不用返回数据
*
* @return
*/
public static JsonData buildSuccess() {
return new JsonData(0, null, null);
} /**
* 成功,返回数据
*
* @param data 返回数据
* @return
*/
public static JsonData buildSuccess(Object data) {
return new JsonData(0, data, null);
} /**
* 成功,返回数据
*
* @param code 状态码
* @param data 返回数据
* @return
*/
public static JsonData buildSuccess(int code, Object data) {
return new JsonData(code, data, null);
} /**
* 失败,返回信息
*
* @param msg 返回信息
* @return
*/
public static JsonData buildError(String msg) {
return new JsonData(-1, null, msg);
} /**
* 失败,返回信息和状态码
*
* @param code 状态码
* @param msg 返回信息
* @return
*/
public static JsonData buildError(Integer code, String msg) {
return new JsonData(code, null, msg);
} public Integer getCode() {
return code;
} public void setCode(Integer code) {
this.code = code;
} public Object getData() {
return data;
} public void setData(Object data) {
this.data = data;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} @Override
public String toString() {
return "JsonData{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\'' +
'}';
}
}
JsonData.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
//扫描mapper
@MapperScan(value = "com.ybchen.springboot_shiro.dao")
public class SpringbootShiroApplication { public static void main(String[] args) {
SpringApplication.run(SpringbootShiroApplication.class, args);
} }
SpringbootShiroApplication.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
server.port=12888
#============数据库=================
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shiro_2?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
# 使用阿里巴巴druid数据源,默认使用自带的
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 开启控制台打印sql
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# mybatis下划线转驼峰配置
mybatis.configuration.map-underscore-to-camel-case=true
application.properties
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro; import org.apache.shiro.crypto.hash.SimpleHash;
import org.junit.Test; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 10:12 下午
* @Versiion:1.0
*/
public class Md5Test {
@Test
public void testMd5(){
String hashName="md5";
String pwd="123";
SimpleHash simpleHash = new SimpleHash(hashName, pwd, null, 2);
System.out.println(simpleHash);
}
}
Md5Test.java
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ybchen</groupId>
<artifactId>springboot_shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_shiro</name>
<description>SpringBoot整合Shiro</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.0</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
pom.xml
项目源码
链接: https://pan.baidu.com/s/1adjwICKge83YcPycE8ZaEQ 密码: if9s
项目postman测试
127.0.0.1:12888/pub/index 127.0.0.1:12888/pub/not_permit 127.0.0.1:12888/pub/need_login 127.0.0.1:12888/pub/login 127.0.0.1:12888/authc/video/play_record 127.0.0.1:12888/admin/video/video_list 127.0.0.1:12888/video/add 127.0.0.1:12888/video/update
备注
因为链接较多,就不一一做gif动图了,直接导入项目源码,请求的时候,在header上加入token即可~
Filter过滤器
业务需求
- 一个接口,可以让2个角色中的任意一个访问
- 自定义一个类,继承:AuthorizationFilter
package com.ybchen.springboot_shiro.config; import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.Set; /**
* @Description:自定义Filter
* @Author:chenyanbin
* @Date:2021/1/4 11:14 下午
* @Versiion:1.0
*/
public class CustomRolesOrAuthorizationFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = getSubject(request, response);
//filterChainDefinitionMap.put("/admin/**", "roles[admin,user]"); mappedValue <==> admin,user
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
return true;
}
Set<String> roles = CollectionUtils.asSet(rolesArray);
//当前subject是roles中的任意一个,则有权限访问
for (String role : roles) {
if (subject.hasRole(role)) {
return true;
}
}
return false;
}
}
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
System.out.println("ShiroConfig ShiroFilterFactoryBean 执行");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//如果访问需要登录的某个接口,却没有登录,则调用此接口(如果不是前后端分离,则跳转页面)
shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
//shiroFilterFactoryBean.setLoginUrl("/xxx.jsp");
//登录成功后,跳转的链接,若前后端分离,没必要设置这个
//shiroFilterFactoryBean.setSuccessUrl("");
//登录成功,未授权会调用此方法
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit"); //设置自定义Filter
Map<String, Filter> filterMap=new LinkedHashMap<>();
filterMap.put("roleOrFilter",new CustomRolesOrAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap); //拦截路径,必须使用:LinkedHashMap,要不然拦截效果会时有时无,因为使用的是无序的Map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//key=正则表达式路径,value=org.apache.shiro.web.filter.mgt.DefaultFilter
//退出过滤器
filterChainDefinitionMap.put("/logout", "logout");
//匿名可以访问,游客模式
filterChainDefinitionMap.put("/pub/**", "anon");
//登录用户才可以访问
filterChainDefinitionMap.put("/authc/**", "authc");
//管理员角色才能访问
// filterChainDefinitionMap.put("/admin/**", "roles[admin,user]");
filterChainDefinitionMap.put("/admin/**", "roleOrFilter[admin,user]");
//有编辑权限才能访问
filterChainDefinitionMap.put("/video/update", "perms[video_update]");
//authc:url必须通过认证才可以访问
//anon:url可以匿名访问
//过滤链是顺序执行,从上而下,一般把/**,放到最下面
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
Redis整合CacheManager
原因
授权的时候每次都去查询数据库,对于频繁访问的接口,性能和响应速度比较慢,此处可以使用缓存,提高响应速度,也可以使用Guava(本地内存缓存)。
Redis(分布式缓存)还不了解的小伙伴,在这里我就不一一讲解了,可以看我以前写过的博客。
添加依赖
<!--shiro+redis-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.3.1</version>
</dependency>
在ShiroConfig中添加如下代码
//使用自定义cacheManager
securityManager.setCacheManager(cacheManager()); /**
* 配置redisManager
* @return
*/
public RedisManager getRedisManager(){
RedisManager redisManager=new RedisManager();
redisManager.setHost("127.0.0.1:6379");
//连接那个数据库
redisManager.setDatabase(0);
//设置密码
// redisManager.setPassword("123");
return redisManager;
} /**
* 设置具体cache实现类
* @return
*/
public RedisCacheManager cacheManager(){
RedisCacheManager redisCacheManager=new RedisCacheManager();
redisCacheManager.setRedisManager(getRedisManager());
return redisCacheManager;
}
修改CustomRealm
设置redis缓存过期时间
Redis整合SessionManager
为啥Session也要持久化
重启应用,用户无感知,可以继续以原先的状态继续访问。
修改shiroconfig
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
![SpringBoot整合Shiro权限框架实战 SpringBoot整合Shiro权限框架实战](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9FeHBhbmRlZEJsb2NrU3RhcnQuZ2lm.gif?w=700&webp=1)
package com.ybchen.springboot_shiro.config; import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map; /**
* @Description:
* @Author:chenyanbin
* @Date:2021/1/3 4:12 下午
* @Versiion:1.0
*/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
System.out.println("ShiroConfig ShiroFilterFactoryBean 执行");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//如果访问需要登录的某个接口,却没有登录,则调用此接口(如果不是前后端分离,则跳转页面)
shiroFilterFactoryBean.setLoginUrl("/pub/need_login");
//shiroFilterFactoryBean.setLoginUrl("/xxx.jsp");
//登录成功后,跳转的链接,若前后端分离,没必要设置这个
//shiroFilterFactoryBean.setSuccessUrl("");
//登录成功,未授权会调用此方法
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit"); //设置自定义Filter
Map<String, Filter> filterMap=new LinkedHashMap<>();
filterMap.put("roleOrFilter",new CustomRolesOrAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap); //拦截路径,必须使用:LinkedHashMap,要不然拦截效果会时有时无,因为使用的是无序的Map
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//key=正则表达式路径,value=org.apache.shiro.web.filter.mgt.DefaultFilter
//退出过滤器
filterChainDefinitionMap.put("/logout", "logout");
//匿名可以访问,游客模式
filterChainDefinitionMap.put("/pub/**", "anon");
//登录用户才可以访问
filterChainDefinitionMap.put("/authc/**", "authc");
//管理员角色才能访问
// filterChainDefinitionMap.put("/admin/**", "roles[admin,user]");
filterChainDefinitionMap.put("/admin/**", "roleOrFilter[admin,user]");
//有编辑权限才能访问
filterChainDefinitionMap.put("/video/update", "perms[video_update]");
//authc:url必须通过认证才可以访问
//anon:url可以匿名访问
//过滤链是顺序执行,从上而下,一般把/**,放到最下面
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
} @Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//如果不是前后端分离,不用设置setSessionManager
securityManager.setSessionManager(sessionManager());
//使用自定义cacheManager
securityManager.setCacheManager(cacheManager());
securityManager.setRealm(customRealm());
return securityManager;
} /**
* 配置redisManager
* @return
*/
public RedisManager getRedisManager(){
RedisManager redisManager=new RedisManager();
redisManager.setHost("127.0.0.1:6379");
//连接那个数据库
redisManager.setDatabase(0);
//设置密码
// redisManager.setPassword("123");
return redisManager;
} /**
* 设置具体cache实现类
* @return
*/
public RedisCacheManager cacheManager(){
RedisCacheManager redisCacheManager=new RedisCacheManager();
redisCacheManager.setRedisManager(getRedisManager());
//设置缓存过期时间
redisCacheManager.setExpire(20);
return redisCacheManager;
} /**
* 自定义realm
*
* @return
*/
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
//因为数据库密码存的是明文,所以无需使用双重md5校验
// customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
} /**
* 密码验证器,双重md5
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//设置散列算法,使用md5算法
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列次数,使用2次md5算法,相当于md5(md5(xxx))
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
} /**
* 自定义SessionManager
*
* @return
*/
@Bean
public SessionManager sessionManager() {
CustomSessionManager customSessionManager = new CustomSessionManager();
//超时时间,默认 30分钟,会话超时,单位毫秒
// customSessionManager.setGlobalSessionTimeout(200000);
//配置session持久化
customSessionManager.setSessionDAO(redisSessionDAO());
return customSessionManager;
} /**
* 自定义session持久化
* @return
*/
public RedisSessionDAO redisSessionDAO(){
RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
redisSessionDAO.setRedisManager(getRedisManager());
return redisSessionDAO;
}
}
ShiroConfig.java
Shiro整合Redis后的源码
链接: https://pan.baidu.com/s/1cNQfBiw50A-U5izzOQclpw 密码: 6wqt