sa-token+json文件实现简单的权限控制

步骤tips:

  1. text
    复制代码
    1.准备权限文件json格式的 并加载这个文件的权限内容到一个自己设计的对象中,然后提供一些获取权限的方法
  2. text
    复制代码
    2.创建一个StpKit门面类 新建一个账号体系
  3. text
    复制代码
    3.实现StpInterface接口 该接口是实现注解鉴权的核心,它给sa-token提供权限信息和角色信息
  4. text
    复制代码
    4.自定义注解SaSpaceCheckPermission
  5. text
    复制代码
    5.写一个配置类配置注解鉴权和注解合并
  6. text
    复制代码
    准备数据模型(这里有关数据的操作全都是模拟为了简化没有使用数据库)
  7. 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.登录

image.png

2.查看当前用户的权限

image.png

3.查看图片列表

image.png

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

image.png

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP