一.说明
Shiro是一个安全框架,项目中主要用它做认证,授权,加密,以及用户的会话管理,虽然Shiro没有SpringSecurity功能更丰富,但是它轻量,简单,在项目中通常业务需求Shiro也都能胜任.二.项目环境
MyBatis-Plus版本: 3.1.0SpringBoot版本:2.1.5
JDK版本:1.8
Shiro版本:1.4
Shiro-redis插件版本:3.1.0
数据表(SQL文件在项目中):数据库中测试号的密码进行了加密,密码皆为123456
数据表名 | 中文表名 | 备注说明 |
---|---|---|
sys_user | 系统用户表 | 基础表 |
sys_menu | 权限表 | 基础表 |
sys_role | 角色表 | 基础表 |
sys_role_menu | 角色与权限关系表 | 中间表 |
sys_user_role | 用户与角色关系表 | 中间表 |
Maven依赖如下:
<dependencies>
配置如下:
# 配置端口
server:
port: 8764
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/my_shiro?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
# Redis数据源
redis:
host: localhost
port: 6379
timeout: 6000
password: 123456
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
# mybatis-plus相关配置
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置
global-config:
db-config:
#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
field-strategy: NOT_EMPTY
#数据库类型
db-type: MYSQL
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 返回map时true:当查询数据为空时字段返回为null,false:不加这个查询数据为空时,字段将被隐藏
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
三.编写项目基础类
用户实体,Dao,Service等在这里省略,请参考源码编写Exception类来处理Shiro权限拦截异常
/**
* @Description 自定义异常
* @Author Sans
* @CreateTime 2019/6/15 22:56
*/
创建SHA256Util加密工具
/**
* @Description Sha-256加密工具
* @Author Sans
* @CreateTime 2019/6/12 9:27
*/
创建Spring工具
/**
* @Description Spring上下文工具类
* @Author Sans
* @CreateTime 2019/6/17 13:40
*/
创建Shiro工具
/**
* @Description Shiro工具类
* @Author Sans
* @CreateTime 2019/6/15 16:11
*/
创建Shiro的SessionId生成器
/**
* @Description 自定义SessionId生成器
* @Author Sans
* @CreateTime 2019/6/11 11:48
*/
四.编写Shiro核心类
创建Realm用于授权和认证/**
* @Description Shiro权限匹配和账号密码匹配
* @Author Sans
* @CreateTime 2019/6/15 11:27
*/
创建SessionManager类
/**
* @Description 自定义获取Token
* @Author Sans
* @CreateTime 2019/6/13 8:34
*/
创建ShiroConfig配置类
/**
* @Description Shiro配置类
* @Author Sans
* @CreateTime 2019/6/10 17:42
*/
五.实现权限控制
Shiro可以用代码或者注解来控制权限,通常我们使用注解控制,不仅简单方便,而且更加灵活.Shiro注解一共有五个:注解名称 | 说明 |
---|---|
RequiresAuthentication | 使用该注解标注的类,方法等在访问时,当前Subject必须在当前session中已经过认证. |
RequiresGuest | 使用该注解标注的类,方法等在访问时,当前Subject可以是“gust”身份,不需要经过认证或者在原先的session中存在记录. |
RequiresUser | 验证用户是否被记忆,有两种含义:一种是成功登录的(subject.isAuthenticated()结果为true);另外一种是被记忆的(subject.isRemembered()结果为true). |
RequiresPermissions | 当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法.如果没有权限,则方法不会执行还会抛出AuthorizationException异常. |
RequiresRoles | 当前Subject必须拥有所有指定的角色时,才能访问被该注解标注的方法.如果没有角色,则方法不会执行还会抛出AuthorizationException异常. |
一般情况下我们在项目中做权限控制,使用最多的是RequiresPermissions和RequiresRoles,允许存在多个角色和权限,默认逻辑是AND,也就是同时拥有这些才可以访问方法,可以在注解中以参数的形式设置成OR
示例
//拥有一个角色就可以访问
使用顺序:Shiro注解是存在顺序的,当多个注解在一个方法上的时候,会逐个检查,知道全部通过为止,默认拦截顺序是:RequiresRoles->RequiresPermissions->RequiresAuthentication-> RequiresUser->RequiresGuest
示例
//拥有ADMIN角色同时还要有sys:role:info权限
@RequiresRoles(value={"ADMIN")
@RequiresPermissions("sys:role:info")
创建UserRoleController角色拦截测试类
/**
* @Description 角色测试
* @Author Sans
* @CreateTime 2019/6/19 11:38
*/
创建UserMenuController权限拦截测试类
/**
* @Description 权限测试
* @Author Sans
* @CreateTime 2019/6/19 11:38
*/
创建UserLoginController登录类
/**
* @Description 用户登录
* @Author Sans
* @CreateTime 2019/6/17 15:21
*/
六.POSTMAN测试
登录成功后会返回TOKEN,因为是单点登录,再次登陆的话会返回新的TOKEN,之前Redis的TOKEN就会失效了当第一次访问接口后我们可以看到缓存中已经有权限数据了,在次访问接口的时候,Shiro会直接去缓存中拿取权限,注意访问接口时候要设置请求头.
ADMIN这个号现在没有sys:info:all这个权限的,所以无法访问getInfoAll接口,我们要动态分配权限后,要清掉缓存,在访问接口时候,Shiro会去重新执行授权方法,之后再次把权限和角色数据放入缓存中
访问添加权限测试接口,因为是测试,我把增加权限的用户ADMIN写死在里面了,权限添加后,调用工具类清掉缓存,我们可以发现,Redis中已经没有缓存了
再次访问getInfoAll接口,因为缓存中没有数据,Shiro会重新授权查询权限,拦截通过
七.项目源码
码云: gitee.com/liselotte/spring-boot-shiro-demoGitHub:github.com/xuyulong2017/my-java-demo
作者:Sans_
链接:juejin.im/post/5d087d605188256de9779e64