章节索引 :

这门课程中,我们使用到了开源的Sa-Token框架。说到Sa-Token框架,有的同学内心产生怀疑:这个框架能用在实战当中吗?这个尽可放心,用在实战当中毫无压力,而且这个框架一直都在不断的迭代升级,所以功能越来越丰富。其Sa-Token的权限验证与授权过程,与Shiro非常类似,只不过设计的更加简单,直接跟JWT融合在了一起。我们写少量的代码就能把Sa-Token整合到SpringBoot项目中。

Sa-Token框架的开源地址(http://sa-token.dev33.cn/)大家可以用浏览器访问,关于该框架的手册文档可以访问(https://sa-token.cc/doc.html#/ )这个网址

图片描述

Sa-Token能做什么

  • 登录验证 —— 轻松登录鉴权,并提供五种细分场景值
  • 权限验证 —— 适配RBAC权限模型,不同角色不同授权
  • Session会话 —— 专业的数据缓存中心
  • 踢人下线 —— 将违规用户立刻清退下线
  • 账号封禁 —— 封禁指定账号,使其无法登陆,还可指定解封时间
  • 持久层扩展 —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
  • 分布式会话 —— 提供jwt集成和共享数据中心两种分布式会话方案
  • 微服务网关鉴权 —— 适配Gateway、Soul、Zuul等常见网关组件的请求拦截认证
  • 单点登录 —— 一处登录,处处通行
  • 临时Token验证 —— 解决短时间的Token授权问题
  • 模拟他人账号 —— 实时操作任意用户状态数据
  • 临时身份切换 —— 将会话身份临时切换为其它账号
  • 无Cookie模式 —— APP、小程序等前后台分离场景
  • 同端互斥登录 —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录
  • 多账号认证体系 —— 比如一个商城项目的user表和admin表分开鉴权
  • 花式token生成 —— 内置六种token风格,还可自定义token生成策略
  • 注解式鉴权 —— 优雅的将鉴权与业务代码分离
  • 路由拦截式鉴权 —— 根据路由拦截鉴权,可适配restful模式
  • 自动续签 —— 提供两种token过期策略,灵活搭配使用,还可自动续签
  • 会话治理 —— 提供方便灵活的会话查询接口
  • 记住我模式 —— 适配[记住我]模式,重启浏览器免验证
  • 密码加密 —— 提供密码加密模块,可快速MD5、SHA1、SHA256、AES、RSA加密
  • 全局侦听器 —— 在用户登陆、注销、被踢下线等关键性操作时进行一些AOP操作
  • 开箱即用 —— 提供SpringMVC、WebFlux等常见web框架starter集成包,真正的开箱即用

一、导入依赖库

pom.xml文件中,引入相关的依赖库,作用各不相同。

<!--核心库-->
<dependency>
	<groupId>cn.dev33</groupId>
	<artifactId>sa-token-spring-boot-starter</artifactId>
	<version>1.20.0</version>
</dependency>
<!--用Redis缓存授权信息-->
<dependency>
	<groupId>cn.dev33</groupId>
	<artifactId>sa-token-dao-redis</artifactId>
	<version>1.20.0</version>
</dependency>
<!--注解式权限验证-->
<dependency>
	<groupId>cn.dev33</groupId>
	<artifactId>sa-token-spring-aop</artifactId>
	<version>1.20.0</version>
</dependency>

二、修改配置文件

application.yml文件中,定义Sa-Token的配置信息。

sa-token:
  #token名称 (同时也是cookie名称)
  token-name: token
  # token有效期,单位s 默认30天, -1代表永不过期
  timeout: 2592000
  # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
  allow-concurrent-login: true
  # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid

三、权限和角色判定

在本项目中,我们用注解的方式判定用户是否为特定的角色或者拥有某些权限。Sa-Token框架为我们提供了这样的注解。比如说下面的Web方法用到了@SaCheckPermission注解判断用户是否具备ROOT或者AMECT:INSERT权限。

@PostMapping("/insert")
@Operation(summary = "添加罚款记录")
@SaCheckPermission(value = {"ROOT", "AMECT:INSERT"}, mode = SaMode.OR)
public R insert(@Valid @RequestBody InsertAmectForm form) {
	……
}

@SaCheckPermission或者@SaCheckRole注解拦截HTTP请求的时候,会调用特定的Java类来获取用户的权限和角色信息,然后跟注解要求的权限或者角色做匹配,如果能匹配上,就允许HTTP请求调用Web方法,否则就拒绝HTTP请求。话说回来,查询用户权限和角色的若干Java代码需要我们自己写,下面咱们就先从SQL语句开始。

1. 查询用户的权限信息

我们先来学习一下RBAC权限模型。
RBAC权限模型
RBAC的基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。这样做的好处是,不必在每次创建用户时都进行分配权限的操作,只要分配用户相应的角色即可,而且角色的权限变更比用户的权限变更要少得多,这样将简化用户的权限管理,减少系统的开销。

RBAC模型中的权限是由模块和行为合并在一起而产生的,在MySQL中,有模块表(tb_module)行为表(tb_action),这两张表的记录合并在一起就行程了权限记录,保存在权限表(tb_permission)中。

现在知道了权限记录是怎么来的,下面我们看看怎么把权限关联到角色中。传统一点的做法是创建一个交叉表,记录角色拥有什么权限。但是现在MySQL5.7之后引入了JSON数据类型,所以我在角色表(tb_role)中设置的permissions字段,类型是JSON格式的。

到目前为止,JSON类型已经支持索引机制,所以我们不用担心存放在JSON字段中的数据检索速度慢了。MySQL为JSON类型配备了很多函数,我们可以很方便的读写JSON字段中的数据。

接下来我们看看角色是怎么关联到用户的,其实我在用户表(tb_user)上面设置role字段,类型依旧是JSON的。这样我就可以把多个角色关联到某个用户身上了。

TbUserDao.xml文件中,定义searchUserPermissions这个SQL语句。

<select id="searchUserPermissions" parameterType="int" resultType="String">
	SELECT DISTINCT p.permission_name
  FROM tb_user u
  JOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))
  JOIN tb_permission p ON JSON_CONTAINS(r.permissions, CAST(p.id AS CHAR))
  WHERE u.id=#{userId} AND u.status=1;
</select>

TbUserDao.java接口中定义Dao方法。

@Mapper
public interface TbUserDao {
    ……
    public Set<String> searchUserPermissions(int userId);
}

2. 创建StpInterfaceImpl类

com.example.emos.api.config包中创建StpInterfaceImpl.java类,这个Java类就是Sa-Token框架拦截HTTP请求之后调用的类。在这个类中,我们一共要声明两个方法分别用来查询用户实际的权限和角色。然后Sa-Token框架的@SaCheckPermission或者@SaCheckRole注解会根据查询出来的权限和角色,跟注解要求的权限或者角色做匹配。

package com.example.emos.api.config;

import cn.dev33.satoken.stp.StpInterface;
import com.example.emos.api.db.dao.TbUserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Component
public class StpInterfaceImpl implements StpInterface {
    @Autowired
    private TbUserDao userDao;

    /**
     * 返回一个用户所拥有的权限集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginKey) {
        int userId = Integer.parseInt(loginId.toString());
        Set<String> permissions = userDao.searchUserPermissions(userId);
        ArrayList list = new ArrayList();
        list.addAll(permissions);
        return list;
    }

    /**
     * 返回一个用户所拥有的角色标识集合
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginKey) {
        //因为本项目不需要用到角色判定,所以这里就返回一个空的ArrayList对象
        ArrayList<String> list = new ArrayList<String>();
        return list;
    }
}

好了,至此我们就已经配置好了Sa-Token权限验证框架,比我们自己动手配置Shiro+JWT要简单多了。

第一章 搭建开发环境
1-1 导学 1-2 搭建开发环境 1-3 MacOS环境的程序安装 1-4 本课程学习方法介绍 1-5 本章总结
第二章 运行项目工程
2-1 本章介绍 2-2 运行工作流项目 2-3 运行后端SpringBoot项目 2-4 运行移动端和前端项目 2-5 前后端项目分析 2-6 前端页面布局设计 2-7 本章总结
第三章 用户管理模块
3-1 本章介绍 3-2 用户登陆系统的流程说明 3-3 编写用户登陆程序(后端) 3-4 编写用户登陆程序(前端) 3-5 修改密码和退出登陆(后端) 3-6 修改密码和退出登陆(前端) 3-7 查询用户分页数据(后端) 3-8 查询用户分页数据(前端) 3-9 添加新用户(后端) 3-10 添加新用户(前端) 3-11 修改用户信息(后端) 3-12 修改用户信息(前端) 3-13 删除非管理员帐户(后端) 3-14 删除非管理员帐户(前端) 3-15 本章总结
第四章 角色管理
4-1 本章介绍 4-2 查询角色分页数据(后端) 4-3 查询角色分页数据(前端) 4-4 添加新角色(后端) 4-5 添加新角色(前端) 4-6 修改角色信息(后端) 4-7 修改角色信息(前端) 4-8 删除非内置角色(后端) 4-9 删除非内置角色(前端) 4-10 本章总结
第五章 部门管理
5-1 本章介绍 5-2 查询部门分页数据(后端) 5-3 查询部门分页数据(前端) 5-4 添加新部门(后端) 5-5 添加新部门(前端) 5-6 修改部门信息(后端) 5-7 修改部门信息(前端) 5-8 删除无用户的部门(后端) 5-9 删除无用户的部门(前端) 5-10 本章总结
第六章 会议室管理
6-1 本章介绍 6-2 查询会议室分页数据(后端) 6-3 查询会议室分页数据(前端) 6-4 添加新会议室(后端) 6-5 添加新会议室(前端) 6-6 修改会议室信息(后端) 6-7 修改会议室信息(前端) 6-8 删除空闲的会议室(后端) 6-9 删除空闲会议室(前端) 6-10 本章总结
第七章 线下会议管理
7-1 本章介绍 7-2 线下会议日程表(持久层) 7-3 线下会议日程表(业务层&Web层) 7-4 分析线下会议日程表前端设计 7-5 线下会议日程表(前端) 7-6 分析会议申请的执行流程 7-7 用异步线程开启线下会议审批流程 7-8 创建线下会议申请(后端) 7-9 创建线下会议申请(前端) 7-10 线下会议周日历(后端) 7-11 线下会议周日历(前端) 7-12 周日历弹窗浏览会议详情(前端) 7-13 删除线下会议申请(后端) 7-14 删除线下会议申请(前端) 7-15 本章总结 附-1 查询线上会议分页数据(后端) 附-2 查询线上会议分页数据(前端) 附-3 申请线上会议(前端) 附-4 删除线上会议申请(前端)
第八章 会议审批
8-1 章节介绍 8-2 查询会议申请分页数据(后端) 8-3 查询会议申请分页数据(前端) 8-4 查询审批任务详情信息(后端) 8-5 查询审批任务详情信息(前端) 8-6 加载BPMN实时进度图 8-7 审批会议申请(后端) 8-8 审批会议申请(前端) 8-9 本章总结
第九章 TRTC在线视频会议
9-1 本章介绍 9-2 获取用户签名和视频会议室RoomID 9-3 查询参会人,生成视频墙(后端) 9-4 生成视频会议室视频墙(前端) 9-5 如何创建TRTC视频推流 9-6 推送本地视频流,订阅远端视频流 9-7 实现入会签到功能 9-8 实时更新上线参会人列表 9-9 动态显示参会人语音强弱 9-10 挂断TRTC,退出视频会议 9-11 大屏显示某个远端视频 9-12 本地屏幕共享,广播推流 9-13 本章总结
第十章 罚款管理
10-1 本章介绍 10-2 查询罚款分页数据(后端) 10-3 查询罚款分页数据(前端) 10-4 添加新罚款记录(后端) 10-5 添加新罚款记录(前端) 10-6 修改罚款单(后端) 10-7 修改罚款单(前端) 10-8 删除罚款单(后端) 10-9 删除罚款单(前端) 10-10 了解微信Native支付罚款流程 10-11 设置内网穿透,用于接收付款结果 10-12 创建支付订单(持久层&业务层) 10-13 创建支付订单(Web层) 10-14 创建支付订单(前端) 10-15 接收付款结果(后端) 10-16 配置SpringBoot支持WebSo 10-17 推送付款结果 10-18 接收付款结果(前端) 10-19 主动查询付款结果(后端) 10-20 主动查询付款结果(前端) 10-21 本章总结 附-1 查询图表数据(后端) 附-2 显示图表数据(前端)
第十一章 罚款类型管理
11-1 本章介绍 11-2 查询罚款类别分页数据(后端) 11-3 查询罚款类别分页数据(前端) 11-4 添加新罚款类型(后端) 11-5 添加新罚款类型(前端) 11-6 修改罚款类型信息(后端) 11-7 修改罚款类型信息(前端) 11-8 删除罚款类型记录(后端) 11-9 删除罚款类型记录(前端) 11-10 本章总结
第十二章 请假管理
12-1 本章介绍 12-2 查询请假分页数据(后端) 12-3 查询请假分页数据(前端) 12-4 用异步线程开启请假审批 12-5 我要请假(后端) 12-6 我要请假(前端) 12-7 用异步线程关闭请假审批工作流实例 12-8 删除请假申请(后端) 12-9 删除请假申请(前端) 12-10 审批员工请假 12-11 生成请假单(后端) 12-12 生成请假单(前端) 12-13 封装腾讯云存储服务 12-14 执行请假归档(后端) 12-15 上传归档文件(前端) 12-16 执行请假归档(前端) 12-17 本章总结
第十三章 报销管理
13-1 本章介绍 13-2 查询报销分页数据(后端) 13-3 查询报销分页数据(前端) 13-4 用异步线程开启报销审批 13-5 创建报销申请(后端) 13-6 创建报销申请(前端) 13-7 生成PDF报销单(后端) 13-8 生成PDF报销单(前端) 13-9 审批报销申请 13-10 删除报销申请(后端) 13-11 删除报销申请(前端) 13-12 本章总结
第十四章 部署Emos项目
14-1 本章介绍 14-2 选购云主机 14-3 安装Docker环境 14-4 Docker中安装程序 14-5 在Docker中部署Java项目 14-6 在Docker中部署前端项目 14-7 本章总结 附录1 为云主机配置域名
第十五章 扩展功能
15-1 微信扫码登陆(后端生成二维码图片) 15-2 微信扫码登陆(前端加载二维码) 15-3 微信扫码登陆(微信小程序) 15-4 NFC扫码功能简介 15-5 NFC扫码识别
第十六章 员工离职
16-1 员工离职(一) 16-2 员工离职(二) 16-3 调试员工离职功能
第十七章 工作流
17-1 Activiti简介 17-2 创建工作流项目 17-3 BPMN入门 17-4 任务审批 16-5 会议审批工作流(一) 16-6 会议审批工作流(二) 16-7 审批工作流
附录
附录1 创建SpringBoot项目 附录2 集成常用工具库 附录3 整合权限验证与授权 附录4 允许跨域请求 附录5 封装全局异常 附录6 全局处理异常 附录7 开启Java异步执行 附录8 抵御XSS攻击 附录9 创建分页数据封装类