Sa-Token是一个轻量级Java权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题
框架集成简单、开箱即用、API设计清爽,功能十分强大
Sa-Token对于权限登录有着更为简洁的API,省下了很多繁琐的固定要写的代码
能做些什么?
登录验证 —— 单端登录、多端登录、同端互斥登录、七天内免登录
权限验证 —— 权限认证、角色认证、会话二级认证
Session会话 —— 全端共享Session、单端独享Session、自定义Session
踢人下线 —— 根据账号id踢人下线、根据Token值踢人下线
账号封禁 —— 指定天数封禁、永久封禁、设定解封时间
持久层扩展 —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
分布式会话 —— 提供jwt集成、共享数据中心两种分布式会话方案
微服务网关鉴权 —— 适配Gateway、Soul、Zuul等常见网关的路由拦截认证
单点登录 —— 内置三种单点登录模式:无论是否跨域、是否共享Redis,都可以搞定
二级认证 —— 在已登录的基础上再次认证,保证安全性
独立Redis —— 将权限缓存与业务缓存分离
临时Token验证 —— 解决短时间的Token授权问题
模拟他人账号 —— 实时操作任意用户状态数据
临时身份切换 —— 将会话身份临时切换为其它账号
前后台分离 —— APP、小程序等不支持Cookie的终端
同端互斥登录 —— 像QQ一样手机电脑同时在线,但是两个手机上互斥登录
多账号认证体系 —— 比如一个商城项目的user表和admin表分开鉴权
花式token生成 —— 内置六种Token风格,还可:自定义Token生成策略、自定义Token前缀
注解式鉴权 —— 优雅的将鉴权与业务代码分离
路由拦截式鉴权 —— 根据路由拦截鉴权,可适配restful模式
自动续签 —— 提供两种Token过期策略,灵活搭配使用,还可自动续签
会话治理 —— 提供方便灵活的会话查询接口
记住我模式 —— 适配[记住我]模式,重启浏览器免验证
密码加密 —— 提供密码加密模块,可快速MD5、SHA1、SHA256、AES、RSA加密
全局侦听器 —— 在用户登陆、注销、被踢下线等关键性操作时进行一些AOP操作
开箱即用 —— 提供SpringMVC、WebFlux等常见web框架starter集成包,真正的开箱即用
单点登录
sa-token针对不同情况提供了三种不同的解决方案
前端同域 + 后端同Redis | 共享Cookie同步会话 |
---|---|
前端不同域 + 后端同Redis | URL重定向传播会话 |
前端不同域 + 后端不同Redis | Http请求获取会话 |
如何选择就是看自己的系统设计了,接下来我会用前端同域后端同redis的方案来实践一下
白话:其实就是单体架构的小Demo,如果你是分布式等设计架构可以参考23模式
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.9version>
dependency>
<dependency>
<groupId>cn.dev33groupId>
<artifactId>sa-token-spring-boot-starterartifactId>
<version>1.8.0version>
dependency>
dependencies>
一些非必要的Sa-Token配置
# 应用服务 WEB 访问端口
server:
port: 8080
spring:
application:
name: sa-token
# sa-token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: satoken
# token有效期,单位s 默认30天, -1代表永不过期
timeout: 60
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
allow-concurrent-login: false
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
# token风格
token-style: uuid
编写一个随意的Controller和一些随意的接口
package com.demo.satoken.controller;
import cn.dev33.satoken.stp.StpUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@RestController
@RequestMapping("user")
public class UserController {
@PostMapping("login")
public Boolean login(@RequestParam("username") String username,@RequestParam("password") String password){
if (StringUtils.isBlank(password)) {
return false;
}
RequestAttributes request = RequestContextHolder.getRequestAttributes();
StpUtil.setLoginId(request.getSessionId());
return true;
}
@GetMapping("isLogin")
public Boolean isLogin(){
RequestAttributes request = RequestContextHolder.getRequestAttributes();
return StpUtil.isLogin();
}
@GetMapping("getLoginId")
public String getLoginId(){
return StpUtil.getLoginId()+"";
}
@GetMapping("logout")
public String logout(){
StpUtil.logout();
return StpUtil.getLoginId()+"";
}
@GetMapping("logoutByLoginId")
public Boolean logoutByLoginId(){
StpUtil.logoutByLoginId(RequestContextHolder.getRequestAttributes().getSessionId());
return true;
}
}
大家可以试着用PostMan或者自己写个极简页面测试一下接口,
一些常用API
StpUtil.login(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
StpUtil.logout(); // 当前会话注销登录
StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
StpUtil.getSession(); // 获取当前账号id的Session
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
StpUtil.login(10001, "PC"); // 指定设备标识登录
StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号
一个极简的Demo完成,其实这个框架真的没有什么学习成本,必要时可以去看官方文档,每个功能都可以一行代码搞定,有什么不懂的可以留言私信我!