SA-TOKEN认证授权快速上手
- SaToken简介
- 认证授权实现
- 1 创建5张测试基础表
- 2 配置文件
- 3 Sa-Token的全局拦截器
- 4 自定义权限认证接口扩展
- 5 SaToken用户控制层
- 测试验证
- 用户2登录验证权限
- 用户1登录验证权限
- 项目代码结构
SaToken简介
SaToken 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。Sa-Token 旨在以简单、优雅的方式完成系统的权限认证部分。SaToken官网,原理如下
认证授权实现
1 创建5张测试基础表
利用经典RBAC理论,创建5张基础表,用于模拟用户的角色和权限功能。
users用户表
role角色表
role_users角色用户表
promission权限表
role_promission角色权限表
可以看到
用户1zhangsan拥有admin和guest角色,拥有user-read、user-write、product-read、product-read四个权限。
用户2拥有guest角色,拥有user-read、product-read两个权限。
2 配置文件
pom.xml引入依赖
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.38.0</version>
</dependency>
application-dev.yml增加配置
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: uuid
# 是否输出操作日志
is-log: true
3 Sa-Token的全局拦截器
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}
4 自定义权限认证接口扩展
自定义接口实现SaToken框架的StpInterface接口,自动帮我们进行执行业务逻辑(获取权限集合,获取角色集合)
/**
* 自定义权限认证接口扩展,Sa-Token 将从此实现类获取每个账号拥有的权限码
* 只要实现了SaToken的StpInterface接口,
* 并且加了@Component被SpringBoot管理,框架就会自动帮我们进行执行业务逻辑
*
* @author huahua
* @since 2024/8/23
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Resource
private JdbcTemplate jdbcTemplate;
// 权限认证校验SaCheckPermission,SaCheckRole注解,必须具有指定权限才能进入该方法。
// 可以标注在方法、类上(效果等同于标注在此类的所有方法上)
/**
* 根据登录id和登录类型获取用户权限列表,返回一个账号所拥有的 权限 码集合
* <p>
* 该方法通过查询数据库,获取指定用户所拥有的所有权限代码
* 查询涉及3张自定义报表:role_user角色用户关联表、role_promission角色权限关联表、promisssion权限表
* 查询条件为用户id,连接3个表获取当前用户所有角色权限信息,从而提取权限代码
*
* @param loginId 用户登录id
* @param loginType 登录类型
* @return 权限列表
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
System.out.println("读取权限列表");
List<String> list = new ArrayList<>();
// 通过用户id查询此id对应的权限列表
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select distinct promission_code from role_users ru,role_promission rp,promission p" +
" where ru.role_id = rp.role_id and rp.promission_id = p.permission_id and ru.user_id = ?", loginId);
for (Map<String, Object> map : maps) {
list.add(map.get("promission_code").toString());
}
return list;
}
/**
* 根据登录id和登录类型获取用户权限列表,返回一个账号所拥有的 角色 码集合
*
* @param loginId 用户登录id
* @param loginType 登录类型
* @return 角色列表
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
List<String> list = new ArrayList<>();
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select distinct r.role_code from role_users ru,role r where ru.role_id = r.role_id and ru.user_id = ?", loginId);
for (Map<String, Object> map : maps) {
list.add(map.get("role_code").toString());
}
return list;
}
}
5 SaToken用户控制层
/**
* sa-token用户控制层
*
* @author huahua
* @DATE 2024/8/23
**/
@RestController
@RequestMapping("/user/")
public class UserController {
@Resource
private JdbcTemplate jdbcTemplate;
// 测试登录,浏览器访问: http://localhost:8086/user/doLogin?username=lisi&password=lisi
@RequestMapping("doLogin")
public SaResult doLogin(String username, String password) {
List<Map<String, Object>> list =
jdbcTemplate.queryForList("select user_id from users where user_name = ? and password = ?", username, password);
if (list.isEmpty()) {
return SaResult.error("用户名或密码错误");
} else {
StpUtil.login(list.get(0).get("user_id"));
return SaResult.ok("登录成功");
}
}
// 查询登录状态,浏览器访问: http://localhost:8086/user/isLogin
@RequestMapping("isLogin")
public SaResult isLogin() {
return SaResult.ok("是否登录:" + StpUtil.isLogin());
}
/**
* 查询用户信息接口,需要具备自定义的‘user-query’权限
*
* @return SaResult 操作结果,返回成功状态
*/
@SaCheckPermission("user-read")
@GetMapping("findUsers")
public SaResult findUsers() {
return SaResult.ok();
}
/**
* 创建用户的接口,需具备‘user-write’或'write'权限之一
* SaMode.AND, 标注一组权限,会话必须全部具有才可通过校验。
* SaMode.OR, 标注一组权限,会话只要具有其一即可通过校验。
*
* @return SaResult 操作结果,返回成功状态
*/
@SaCheckPermission(value = {"user-write", "write"}, mode = SaMode.OR)
@GetMapping("createUser")
public SaResult createUser() {
/*
// 查询权限信息 ,如果当前会话未登录,会返回一个空集合
List<String> permissionList = StpUtil.getPermissionList();
System.out.println("当前登录账号拥有的所有权限:" + permissionList);
// 查询角色信息 ,如果当前会话未登录,会返回一个空集合
List<String> roleList = StpUtil.getRoleList();
System.out.println("当前登录账号拥有的所有角色:" + roleList);
*/
return SaResult.ok();
}
/**
* 删除用户
* 代表需要拥有角色 admin 才可以操作
*
* @return SaResult 操作结果,返回成功状态
*/
@SaCheckRole("admin")
@GetMapping("/deleteUser")
public SaResult deleteUser(){
return SaResult.ok();
}
}
测试验证
用户2登录验证权限
发现用户2,没有deleteUser和createUser用户权限,因为SaCheckRole和SaCheckPermission框架注解帮我们做了权限管控!
用户1登录验证权限
项目代码结构
项目结构如下,源码demo-springboot-mybatisplus,欢迎star