sa-token+json文件实现简单的权限控制
步骤tips:
-
▼text复制代码
1.准备权限文件json格式的 并加载这个文件的权限内容到一个自己设计的对象中,然后提供一些获取权限的方法 -
▼text复制代码
2.创建一个StpKit门面类 新建一个账号体系 -
▼text复制代码
3.实现StpInterface接口 该接口是实现注解鉴权的核心,它给sa-token提供权限信息和角色信息 -
▼text复制代码
4.自定义注解SaSpaceCheckPermission -
▼text复制代码
5.写一个配置类配置注解鉴权和注解合并 -
▼text复制代码
准备数据模型(这里有关数据的操作全都是模拟为了简化没有使用数据库) -
▼text复制代码
写接口Controller标注解测试效果
准备权限文件并加载
▼text复制代码{ "permissions": [ { "key": "spaceUser:manage", "name": "成员管理", "description": "管理空间成员,添加或移除成员" }, { "key": "picture:view", "name": "查看图片", "description": "查看空间中的图片内容" }, { "key": "picture:upload", "name": "上传图片", "description": "上传图片到空间中" }, { "key": "picture:edit", "name": "修改图片", "description": "编辑已上传的图片信息" }, { "key": "picture:delete", "name": "删除图片", "description": "删除空间中的图片" } ], "roles": [ { "key": "viewer", "name": "浏览者", "permissions": [ "picture:view" ], "description": "查看图片" }, { "key": "editor", "name": "编辑者", "permissions": [ "picture:view", "picture:upload", "picture:edit" ], "description": "查看图片、上传图片、修改图片" }, { "key": "admin", "name": "管理员", "permissions": [ "spaceUser:manage", "picture:view", "picture:upload", "picture:edit", "picture:delete" ], "description": "成员管理、查看图片、上传图片、修改图片、删除图片" } ] }
SpaceUserAuthConfig
▼text复制代码package org.example.authlearn.model.entity; import lombok.Data; import java.io.Serializable; import java.util.List; /** * 空间成员权限配置 */ @Data public class SpaceUserAuthConfig implements Serializable { /** * 权限列表 */ private List<SpaceUserPermission> permissions; /** * 角色列表 */ private List<SpaceUserRole> roles; private static final long serialVersionUID = 1L; }
SpaceUserAuthManager
▼package复制代码import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.json.JSONUtil; import org.example.authlearn.constant.SpaceRoleEnum; import org.example.authlearn.model.entity.SpaceUserAuthConfig; import org.example.authlearn.model.entity.SpaceUserRole; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * 空间成员权限管理 */ @Component public class SpaceUserAuthManager { public static final SpaceUserAuthConfig SPACE_USER_AUTH_CONFIG; static { // 从 resources/biz 目录加载权限配置 String json = ResourceUtil.readUtf8Str("biz/spaceUserAuthConfig.json"); SPACE_USER_AUTH_CONFIG = JSONUtil.toBean(json, SpaceUserAuthConfig.class); } /** * 根据角色获取权限列表 */ public List<String> getPermissionsByRole(String role) { if (role == null || role.trim().isEmpty()) { return new ArrayList<>(); } return SPACE_USER_AUTH_CONFIG.getRoles().stream() .filter(r -> r.getKey().equals(role)) .findFirst() .map(SpaceUserRole::getPermissions) .orElse(new ArrayList<>()); } /** * 获取所有权限列表(用于调试和展示) */ public List<String> getAllPermissions() { List<String> allPermissions = new ArrayList<>(); SPACE_USER_AUTH_CONFIG.getRoles().forEach(role -> { if (role.getPermissions() != null) { allPermissions.addAll(role.getPermissions()); } }); return allPermissions.stream().distinct().toList(); } /** * 检查角色是否包含指定权限 */ public boolean checkPermission(String role, String permission) { List<String> permissions = getPermissionsByRole(role); return permissions.contains(permission); } /** * 获取管理员权限(特殊处理) */ public List<String> getAdminPermissions() { return getPermissionsByRole(SpaceRoleEnum.ADMIN.getValue()); } }
2.创建一个StpKit门面类 新建一个账号体系
StpKit
▼text复制代码package org.example.authlearn; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import org.springframework.stereotype.Component; /** * StpLogic 门面类,管理项目中所有的 StpLogic 账号体系 * 添加 @Component 注解的目的是确保静态属性 DEFAULT 和 SPACE 被初始化 */ @Component public class StpKit { public static final String SPACE_TYPE = "space"; /** * 默认原生会话对象,项目中目前没使用到 */ public static final StpLogic DEFAULT = StpUtil.stpLogic; /** * Space 会话对象,管理 Space 表所有账号的登录、权限认证 */ public static final StpLogic SPACE = new StpLogic(SPACE_TYPE); }
3.实现StpInterface接口 该接口是实现注解鉴权的核心,它给sa-token提供权限信息和角色信息
StpInterfaceImpl
▼text复制代码package org.example.authlearn.auth; import cn.dev33.satoken.stp.StpInterface; import org.example.authlearn.model.entity.User; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.*; // StpInterfaceImpl.java - 自定义权限加载 @Component public class StpInterfaceImpl implements StpInterface { @Resource private SpaceUserAuthManager spaceUserAuthManager; // 模拟用户数据 private final Map<String, User> userMap = new HashMap<String, User>() {{ put("admin", new User(1L, "admin", "管理员", "admin")); put("editor", new User(2L, "editor", "编辑者", "editor")); put("viewer", new User(3L, "viewer", "浏览者", "viewer")); put("guest", new User(4L, "guest", "游客", "viewer")); }}; @Override public List<String> getPermissionList(Object loginId, String loginType) { User user = userMap.get(loginId.toString()); if (user == null) { return new ArrayList<>(); } return spaceUserAuthManager.getPermissionsByRole(user.getRole()); } @Override public List<String> getRoleList(Object loginId, String loginType) { User user = userMap.get(loginId.toString()); if (user == null) { return new ArrayList<>(); } return Collections.singletonList(user.getRole()); } }
4.自定义注解SaSpaceCheckPermission
SaSpaceCheckPermission
▼text复制代码package org.example.authlearn.auth; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaMode; import org.example.authlearn.StpKit; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; // SaSpaceCheckPermission.java - 自定义权限注解 @SaCheckPermission(type = StpKit.SPACE_TYPE) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface SaSpaceCheckPermission { @AliasFor(annotation = SaCheckPermission.class) String[] value() default {}; @AliasFor(annotation = SaCheckPermission.class) SaMode mode() default SaMode.AND; }
5.写一个配置类配置注解鉴权和注解合并
SaTokenConfigure
▼text复制代码package org.example.authlearn.auth; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.strategy.SaAnnotationStrategy; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.PostConstruct; /** * Sa-Token 开启注解和配置 */ @Configuration public class SaTokenConfigure implements WebMvcConfigurer { // 注册 Sa-Token 拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { // 注册 Sa-Token 拦截器,打开注解式鉴权功能 registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } @PostConstruct public void rewriteSaStrategy() { // 重写Sa-Token的注解处理器,增加注解合并功能 SaAnnotationStrategy.instance.getAnnotation = (element, annotationClass) -> { return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass); }; } }
准备数据模型
User
▼text复制代码package org.example.authlearn.model.entity; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class User { private Long id; private String username; private String nickname; private String role; }
SpaceUserRole
▼text复制代码package org.example.authlearn.model.entity; import lombok.Data; import java.io.Serializable; import java.util.List; /** * 空间用户角色 */ @Data public class SpaceUserRole implements Serializable { /** * 角色键值 */ private String key; /** * 角色名称 */ private String name; /** * 权限列表 */ private List<String> permissions; /** * 角色描述 */ private String description; private static final long serialVersionUID = 1L; }
SpaceUserPermission
▼text复制代码package org.example.authlearn.model.entity; import lombok.Data; import java.io.Serializable; /** * 空间用户权限 */ @Data public class SpaceUserPermission implements Serializable { /** * 权限键值 */ private String key; /** * 权限名称 */ private String name; /** * 权限描述 */ private String description; private static final long serialVersionUID = 1L; }
Picture
▼text复制代码package org.example.authlearn.model.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Picture { private Long id; private String name; private String description; private Long userId; }
ApiResult
▼text复制代码package org.example.authlearn.model.entity; import lombok.Data; @Data public class ApiResult<T> { private int code; private String message; private T data; public ApiResult(int i, String success, T data) { this.code = i; this.message = success; this.data = data; } public static <T> ApiResult<T> success(T data) { return new ApiResult<>(200, "success", data); } public static <T> ApiResult<T> error(String message) { return new ApiResult<>(500, message, null); } }
SpaceRoleEnum
▼text复制代码package org.example.authlearn.constant; /** * 空间角色枚举 */ public enum SpaceRoleEnum { VIEWER("viewer", "浏览者"), EDITOR("editor", "编辑者"), ADMIN("admin", "管理员"); private final String value; private final String desc; SpaceRoleEnum(String value, String desc) { this.value = value; this.desc = desc; } public String getValue() { return value; } public String getDesc() { return desc; } public static SpaceRoleEnum getEnumByValue(String value) { for (SpaceRoleEnum roleEnum : SpaceRoleEnum.values()) { if (roleEnum.getValue().equals(value)) { return roleEnum; } } return null; } }
开发Controller接口
UserController
▼text复制代码package org.example.authlearn.controller; import cn.dev33.satoken.stp.StpUtil; import org.example.authlearn.StpKit; import org.example.authlearn.model.entity.ApiResult; import org.springframework.web.bind.annotation.*; // UserController.java - 用户认证控制器 @RestController @RequestMapping("/user") public class UserController { /** * 用户登录 */ @PostMapping("/login") public ApiResult<String> login(@RequestParam String username) { // 模拟登录,实际项目中需要验证密码 StpKit.SPACE.login(username); return ApiResult.success("登录成功"+ StpKit.SPACE.getTokenValue()); } /** * 用户退出 */ @PostMapping("/logout") public ApiResult<String> logout() { StpKit.SPACE.logout(); return ApiResult.success("退出成功"); } /** * 获取当前用户信息 */ @GetMapping("/info") public ApiResult<Object> getUserInfo() { return ApiResult.success(StpKit.SPACE.getSession().get("user")); } /** * 检查权限 */ @GetMapping("/checkPermission") public ApiResult<Boolean> checkPermission(@RequestParam String permission) { boolean hasPermission = StpKit.SPACE.hasPermission(permission); return ApiResult.success(hasPermission); } }
PictureController
▼text复制代码package org.example.authlearn.controller; import cn.dev33.satoken.annotation.SaMode; import org.example.authlearn.auth.SaSpaceCheckPermission; import org.example.authlearn.model.entity.ApiResult; import org.example.authlearn.model.entity.Picture; import org.springframework.web.bind.annotation.*; import java.util.Arrays; import java.util.List; // PictureController.java - 图片管理控制器 @RestController @RequestMapping("/picture") public class PictureController { // 模拟图片数据 private final List<Picture> pictureList = Arrays.asList( new Picture(1L, "风景图1", "美丽的风景", 1L), new Picture(2L, "人物图1", "人物肖像", 2L), new Picture(3L, "动物图1", "可爱动物", 1L) ); /** * 查看图片列表 - 需要 picture:view 权限 */ @SaSpaceCheckPermission("picture:view") @GetMapping("/list") public ApiResult<List<Picture>> getPictureList() { return ApiResult.success(pictureList); } /** * 查看图片详情 - 需要 picture:view 权限 */ @SaSpaceCheckPermission("picture:view") @GetMapping("/{id}") public ApiResult<Picture> getPicture(@PathVariable Long id) { Picture picture = pictureList.stream() .filter(p -> p.getId().equals(id)) .findFirst() .orElse(null); return picture != null ? ApiResult.success(picture) : ApiResult.error("图片不存在"); } /** * 上传图片 - 需要 picture:upload 权限 */ @SaSpaceCheckPermission("picture:upload") @PostMapping("/upload") public ApiResult<String> uploadPicture(@RequestBody Picture picture) { return ApiResult.success("图片上传成功: " + picture.getName()); } /** * 编辑图片 - 需要 picture:edit 权限 */ @SaSpaceCheckPermission("picture:edit") @PutMapping("/{id}") public ApiResult<String> updatePicture(@PathVariable Long id, @RequestBody Picture picture) { return ApiResult.success("图片更新成功: " + id); } /** * 删除图片 - 需要 picture:delete 权限 */ @SaSpaceCheckPermission("picture:delete") @DeleteMapping("/{id}") public ApiResult<String> deletePicture(@PathVariable Long id) { return ApiResult.success("图片删除成功: " + id); } /** * 管理空间成员 - 需要 spaceUser:manage 权限 */ @SaSpaceCheckPermission("spaceUser:manage") @GetMapping("/space/users") public ApiResult<String> manageSpaceUsers() { return ApiResult.success("空间成员管理操作成功"); } /** * 复杂权限校验:需要同时有查看和编辑权限 */ @SaSpaceCheckPermission(value = {"picture:view", "picture:edit"}, mode = SaMode.AND) @PostMapping("/batch-edit") public ApiResult<String> batchEditPictures() { return ApiResult.success("批量编辑操作成功"); } }
补充的yml配置
▼text复制代码# application.yml server: port: 8080 servlet: context-path: / spring: application: name: permission-demo # Sa-Token 配置 sa-token: token-name: Authorization timeout: 86400 active-timeout: 3600 is-concurrent: true is-share: true token-style: uuid is-log: true
测试
1.登录

2.查看当前用户的权限

3.查看图片列表

4.上传图片 失败因为没有权限

评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
作者分享
Day 8 11.27
✅ 今天做了:
jvm五种结构(方法区、堆、虚拟机栈、计数器、本地方法栈)
Redis:为什么要有哨兵
rabbitmq:amqp client demo
⏰ 明天计划:
📚 今日感悟:
1
Day 7(11.25补)
✅ 今天做了:
1.图解Redis 的过期删除和内存淘汰(有些没搞懂)
2.图解Redis的 Redis大key 对AOF和RDB快照的影响以及如何解决
3.Rabbit MQ 的如何保证消息的可靠性(发送者的可靠性、MQ消息队列的可靠性、消费者的可靠性、业务层面的兜底方案)
⏰ 明天计划:
📚 今日感悟:
2
Day 6(11.24补)
✅ 今天做了:学习了 redis 的AOF和RDB
⏰ 明天计划:
📚 今日感悟:课太多了 摆烂了
2
Day 5(11.22)
✅ 今天做了:
1.重新学习了图解redis的常见数据结构的底层数据结构原理 之搞懂了一般左右😅
2.刷了面试鸭 :
3.学习rabbitmq:
⏰ 明天计划:
📚 今日感悟:
1
Day 4(11.20补)
✅ 今天做了:
1.完成了一份Cisco Packet Tracer的VLAN实验(学校实验真废时间 一堆规定😂)
2.安装了docker和rabbitmq
⏰ 明天计划:
📚 今日感悟:
1
