1 Spring Boot集成Sa-token
1.1 前言
Sa-token是一款高可用的权限认证框架,他带我们用最简化的配置完成用 spring security 需要进行大量配置的才能完成的工作。
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。
官网:https://sa-token.dev33.cn/
源码:https://gitee.com/dromara/sa-token
1.2 集成Sa-token
在我们的基础开发版本中,我们只需要引入最基础依赖,现在的最新官方版本为:1.30.0 建议使用最新版本,如果在你的maven 仓库中没有该版本,需要替换maven 的镜像源,请参考
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.30.0</version>
</dependency>
配置依赖后需要配置spring boot本地自定义配置
# Sa-Token 配置
sa-token:# token名称 (同时也是cookie名称)token-name: satoken# token有效期,单位s 默认30天, -1代表永不过期timeout: 2592000# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒activity-timeout: -1# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)is-share: true# token风格token-style: uuid# 是否输出操作日志is-log: false
按该配置,配置完成后即可完成基础的引入,这里主要配置token 的过期和作用范围。
token:服务端生成的一串加密字符串、以作客户端进行请求的一个“令牌”。. 当用户第一次使用账号密码成功进行登录后,服务器便生成一个Token及Token失效时间并将此返回给客户端,若成功登陆,以后客户端只需在有效时间内带上这个Token前来请求数据即可,无需再次带上用户名和密码。
1.3 基础使用
校验是否成功引入可在启动类下添加该语句
@SpringBootApplication
@EnableScheduling
public class CretApplication {public static void main(String[] args) {SpringApplication.run(CretApplication.class, args);System.out.println("启动成功:Sa-Token配置如下:" + SaManager.getConfig());}
}
当控制台输出我们的配置内容时,证明sa-token 的依赖已经引入,观察输出就会发现sa-token 已经为我们初始化了很多的配置,接下的使用就会非常的简单!
启动成功:Sa-Token配置如下:SaTokenConfig [tokenName=satoken, timeout=2592000, activityTimeout=-1, isConcurrent=true, isShare=true, maxLoginCount=12, isReadBody=true, isReadHead=true, isReadCookie=true, tokenStyle=uuid, dataRefreshPeriod=30, tokenSessionCheckLogin=true, autoRenew=true, tokenPrefix=null, isPrint=true, isLog=false, jwtSecretKey=null, idTokenTimeout=86400, basic=, currDomain=null, checkIdToken=false, cookie=SaCookieConfig [domain=null, path=null, secure=false, httpOnly=false, sameSite=null]]
作为一个权限校验开发框架,他的第一个动作便是针对我们的登录操作,在登录的时候便需要开始使用sa-token里面很强大的一个类‘ StpUtil.class’
// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String,
不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id); // 当前会话注销登录
StpUtil.logout();// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();
只需要通过简单的一句登录,sa-token便已经为我们生成好权限校验的系列组件。如果你觉得这种代码方式的开发太繁琐,不是那么的清晰知道当前的权限,进行简单的校验,就可以开启注解方式的校验。注解式校验的配置如下:
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {// 注册Sa-Token的注解拦截器,打开注解式鉴权功能@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");}
}
在开启拦截器后,我们即可实现注解式开发,像之前使用spring 注解一般。
// 检验当前会话是否已经登录
StpUtil.checkLogin();//检验当前会话是否已经登录
@SaCheckLogin
这里的注解可直接放在一个接口上,这样当一个请求进来的时候sa-token 的拦截器会先从请求中获取自己注入 的标识 sa-token ,这个sa-token 里面包含了系列参数来保证登录的安全正确性。
2 Spring Boot开发Sa-token
上一部分我们介绍了如何通过sa-token 实现最基础的登录认证,在开发过程中我们会对sa-token 的一系列功能进行使用,慕歌将就自己的项目向大家展示sa-token 的一些功能,如登录校验、登录检测、封禁用户,token 校验,多租户模式等功能
2.1 导入maven依赖
<!-- Sa-Token 整合 Redis (使用 jdk 默认序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis</artifactId><version>1.30.0</version></dependency><!-- redis 缓存操作 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--连接池依赖--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
2.2 权限校验
在进行登录验证的同时,进行权限校验也是重要的一环,sa-token通过拦截器,为我们的权限校验进行了拓展,让我们可以在全局工程中随处进行权限控制。并且依赖于上一节介绍的注解式开发,使得整个校验过程更加的简洁,明了。
/*** 注入权限组*/
@Component
public class StpInterfaceImpl implements StpInterface {//权限@AutowiredAdminPowerMapper adminPowerMapper;//角色@AutowiredAdminRolesMapper adminRolesMapperl;/*** 用户权限* @param loginId 登录id* @param s* @return*/@Overridepublic List<String> getPermissionList(Object loginId, String s) {//获得登录的用户id 对应权限List<String> userPermissions = adminPowerMapper.getUserPermissions(loginId);System.out.println("permiassion - list : "+userPermissions);return userPermissions;}/*** 用户角色* @param loginId 登录id* @param s* @return*/@Overridepublic List<String> getRoleList(Object loginId, String s) {//获得登录的用户id 对应角色List<String> userRoles = adminRolesMapperl.getUserRole(loginId);System.out.println("role - list : "+userRoles);return userRoles;}
}
在我的开发中,引入了两层控制,角色表,权限表,进行细颗粒的权限控制,更好保证数据见的隔离。附上我的角色表于权限表的设计源码:
create table cf_admin_power
(id int unsigned auto_increment comment '权限id'primary key,code varchar(32) not null comment '权限码',name char(32) not null comment '权限名',level char(32) not null comment '等级',icon varchar(255) null comment '图标',is_show tinyint unsigned default 1 not null comment '是否显示(0:否,1:是)',status tinyint unsigned default 1 not null comment '状态(1:可用,2:停用,3:已删除)',create_time datetime not null comment '创建时间',update_time datetime not null comment '更新时间'
)comment '权限表
' collate = utf8_unicode_ci;-- auto-generated definition
create table cf_admin_roles
(id int unsigned auto_increment comment '角色id'primary key,name char(32) not null comment '角色名称',role_info char(32) null comment '角色描述',is_super tinyint unsigned default 0 not null comment '是超级管理员(1:是,0:否)',status tinyint unsigned default 1 not null comment '状态(1:可用,2:停用,3:已删除)',create_time datetime null comment '创建时间',update_time datetime null comment '更新时间'
)comment '角色组表' collate = utf8_unicode_ci;
在为用户注入权限后,权限的校验就变得简单起来了,只需要简单的注解,调用即可校验权限。就在这样的一个校验注解,就可以实现用户角色,用户权限的检查
// 角色认证:必须具有指定角色才能进入该方法
@SaCheckRole("super-admin")
// 权限认证:必须具有指定权限才能进入该方法
@SaCheckPermission("user-add")
//三个权限并列,满足一个则通过
@SaCheckPermission(value = {"user-add", "user-all", "user-delete"}, mode = SaMode.OR)
//同时满足角色和权限,通过
@SaCheckPermission(value = "user-add", orRole = "admin")
2.3 token
框架为我们提供了多种token生成方式,以及token 的校验规则,将一个用户标记为登录状态后,该用户就进入sa-token 中进行统一管理。在配置redis 后,即可实现到重启数据不丢失,而且保证分布式环境下多节点的会话一致性。
//登录
StpUtil.login(user.getId());
// 踢下线
StpUtil.kickout(adminUser.getId());
//冻结
StpUtil.disable(adminUser.getId(), -1);
// 获取 Token 相关参数
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
在前后台的开发中,我们可以将登录信息回传,即可实现前端通过token 建立访问,前后端分离。前端可将登录后返回的token 保存,之后每次进行数据访问时携带token ,后端便可以对请求者的权限信息校验。
//回传数据
"data":{11 items"tokenName":"satoken""tokenValue":"6046ddd3-71cd-4509-b9ca-b842790bda72""isLogin":true"loginId":"1002""loginType":"login""tokenTimeout":2592000"sessionTimeout":2591999"tokenSessionTimeout":-2"tokenActivityTimeout":-1"loginDevice":"default-device""tag":NULL
}
//redis 缓存数据
satoken:login:token:6046ddd3-71cd-4509-b9ca-b842790bda72
2.4 多租户模式
在我的开发中,分官网用户和后台用户,他们是完全不同的两组数据,具有各自独立的权限,这时候需要使用到多租户模式,对不同的用户组维护各自的权限。sa-token为我们实现了一种简单的方式,对不同的组加上对应的标签。之后实现sa-token 的校验模式,便可同标准使用方式一样,对自己的用户组校验。
public class StpAdminUtil {//权限组 类型 adminpublic static final String TYPE = "admin";//底层logic 静态类public static StpLogic stpLogic = new StpLogic("admin");public StpAdminUtil() {}public static String getLoginType() {return stpLogic.getLoginType();}public static void setStpLogic(StpLogic stpLogic) {cn.dev33.satoken.stp.StpUtil.stpLogic = stpLogic;SaManager.putStpLogic(stpLogic);}
}/*** 聚合接口*/
@Configuration
public class SaMultiConfig {@Autowiredpublic void rewriteSaStrategy() {// 重写Sa-Token的注解处理器,增加注解合并功能SaStrategy.me.getAnnotation = (element, annotationClass) -> {return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);};}
}/*** 登录认证(User版):只有登录之后才能进入该方法* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)*/
@SaCheckLogin(type = "admin")
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE})
public @interface SaAdminCheckLogin {
}