找回密码
 立即注册
首页 业界区 业界 控制权限系列之(2)手把手教你使用基于角色的权限控制 ...

控制权限系列之(2)手把手教你使用基于角色的权限控制

越蔓蔓 6 天前
前一篇已经分析了多种权限模型,其中比较常用的是基于角色的权限控制。
基于角色的权限控制

表设计:
  1. 用户表
  2. 用户--角色关系表
  3. 角色表
  4. 角色--菜单关系表
  5. 菜单表
复制代码
权限标识格式:
  1. 格式:xxx:xxx:xxx(模块:资源:操作) 三段式
复制代码
权限架构的分层结构:
  1. 应用层 (@RequirePermission注解)
  2.     ↓
  3. 权限验证层 (PermissionValidator)
  4.     ↓
  5. 权限上下文层 (PermissionContext - ThreadLocal)
  6.     ↓
  7. 权限提供层 (PermissionProvider - 数据库/缓存)
  8.     ↓
  9. 权限存储层 (PermissionStorage - Redis/Memory)
复制代码
 
权限架构接口:

权限提供者接口
  1. 1 public interface PermissionProvider {
  2. 2     // 获取用户的所有权限标识
  3. 3     Set<String> getUserPermissions(Object userId);
  4. 4     
  5. 5     // 获取用户角色列表
  6. 6     Set<String> getUserRoles(Object userId);
  7. 7     
  8. 8     // 检查用户是否为超级管理员
  9. 9     boolean isSuperAdmin(Object userId);
  10. 10     
  11. 11     // 刷新用户权限缓存
  12. 12     void refreshUserPermissions(Object userId);
  13. 13 }
复制代码

  • userId 使用 Object 类型,支持 String、Long 等不同ID类型
  • 支持超级管理员逻辑(拥有所有权限)
  • 提供刷新接口,支持权限变更后更新缓存
权限存储接口
  1. 1 public interface PermissionStorage {
  2. 2     // 存储用户权限信息
  3. 3     void storeUserInfo(String token, UserInfo userInfo);
  4. 4     
  5. 5     // 获取用户权限信息
  6. 6     UserInfo getUserInfo(String token);
  7. 7     
  8. 8     // 删除用户权限信息
  9. 9     void removeUserInfo(String token);
  10. 10     
  11. 11     // 刷新用户权限信息
  12. 12     void refreshUserInfo(String token, UserInfo userInfo);
  13. 13 }
复制代码

  • 基于Token存储,支持分布式场景
  • 支持多种存储实现(Redis、Memory、数据库等)
  • 提供刷新接口,支持权限实时更新
权限匹配器接口
  1. 1 public interface PermissionMatcher {
  2. 2     // 匹配权限
  3. 3     boolean match(String requiredPermission, Set<String> userPermissions);
  4. 4     
  5. 5     // 批量匹配(全部满足)
  6. 6     boolean matchAll(Set<String> requiredPermissions, Set<String> userPermissions);
  7. 7     
  8. 8     // 批量匹配(任意一个满足)
  9. 9     boolean matchAny(Set<String> requiredPermissions, Set<String> userPermissions);
  10. 10 }
复制代码

  • 支持多种匹配策略(精确、通配符、正则等)
  • 支持批量匹配(AND/OR逻辑)
  • 可扩展自定义匹配规则
用户信息
  1. 1 public class UserInfo {
  2. 2     private Object userId;                    // 用户ID
  3. 3     private String username;                  // 用户名
  4. 4     private Set<String> permissions;          // 权限集合
  5. 5     private Set<String> roles;                // 角色集合
  6. 6     private boolean superAdmin;               // 是否超级管理员
  7. 7     private Map<String, Object> attributes;   // 扩展属性
  8. 8 }
复制代码

  • 使用 Object 类型支持不同ID类型
  • 提供扩展属性,支持业务字段存储
  • 轻量级设计,便于序列化和传输
权限上下文
  1. 1 public class PermissionContext {
  2. 2     private static final ThreadLocal<UserInfo> USER_INFO_HOLDER = new TransmittableThreadLocal<>();
  3. 4     
  4. 5     public static void set(UserInfo userInfo);
  5. 6     public static UserInfo get();
  6. 7     public static void clear();
  7. 8     
  8. 9     public static boolean hasPermission(String permission);
  9. 10     public static Set<String> getPermissions();
  10. 11 }
复制代码

  • 使用 TransmittableThreadLocal 支持线程池传递
  • 提供便捷方法,简化权限判断
  • 请求结束后自动清理,避免内存泄漏
权限验证器接口
  1. 1 public interface PermissionValidator {
  2. 2     // 验证单个权限
  3. 3     boolean hasPermission(String permission);
  4. 4     
  5. 5     // 验证所有权限(AND)
  6. 6     boolean hasAllPermissions(Set<String> permissions);
  7. 7     
  8. 8     // 验证任意权限(OR)
  9. 9     boolean hasAnyPermission(Set<String> permissions);
  10. 10     
  11. 11     // 验证角色
  12. 12     boolean hasRole(String role);
  13. 13     
  14. 14     // 获取当前用户上下文
  15. 15     UserContext getCurrentUser();
  16. 16 }
复制代码

  • 提供多种验证方式(单个、全部、任意)
  • 支持角色验证
  • 统一权限验证入口
实现策略

抽象权限提供者


  • 提供模板方法,定义权限获取流程
  • 子类只需实现具体查询逻辑
  • 统一处理超级管理员逻辑
  1. 1 public abstract class AbstractPermissionProvider implements PermissionProvider {
  2. 2     
  3. 3     @Override
  4. 4     public Set<String> getUserPermissions(Object userId) {
  5. 5         // 方法:统一处理超管
  6. 6         if (isSuperAdmin(userId)) {
  7. 7             return getAllPermissions();
  8. 8         }
  9. 9         return doGetUserPermissions(userId);
  10. 10     }
  11. 11     
  12. 12     // 子类实现:获取所有权限
  13. 13     protected abstract Set<String> getAllPermissions();
  14. 14     
  15. 15     // 子类实现:查询用户权限
  16. 16     protected abstract Set<String> doGetUserPermissions(Object userId);
  17. 17 }
复制代码
Redis存储


  • 使用Redis存储用户信息(JSON序列化)
  • 支持过期时间配置
  • 支持Key前缀配置
  • 异常处理和日志记录
  1. 1 public class RedisPermissionStorage implements PermissionStorage {
  2. 2     
  3. 3     @Override
  4. 4     public void storeUserInfo(String token, UserInfo userInfo) { 7         redisTemplate.opsForValue().set(key, value, expireSeconds, TimeUnit.SECONDS);
  5. 8     }
  6. 9     
  7. 10     @Override
  8. 11     public UserInfo getUserInfo(String token) {14         return value;
  9. 15     }
  10. 16 }
复制代码

  • 支持 * 和 ? 通配符
  • 例如:sys:user:* 匹配 sys:user:save、sys:user:update 等
  • 使用Spring的 PatternMatchUtils.simpleMatch()
权限过滤器


  • 请求头提取Token
  • 从Storage获取用户信息(如不存在,从Provider加载)
  • 设置到PermissionContext
  • 请求结束后清理上下文
  1. <strong>过滤器流程:</strong><br><br>请求到达
  2.     ↓
  3. 检查排除路径(登录、公开接口等)
  4.     ↓
  5. 提取Token
  6.     ↓
  7. 从Storage获取用户信息
  8.     ↓(如果不存在)
  9. 从Provider加载用户信息 → 存储到Storage
  10.     ↓
  11. 设置到PermissionContext
  12.     ↓
  13. 继续请求处理
  14.     ↓
  15. 清理PermissionContext
复制代码
权限注解 


  • 支持单个权限、多个权限(AND/OR)
  • 支持角色验证
  • 支持自定义错误消息
  1. @Target({ElementType.METHOD, ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface RequirePermission {
  4.     String value() default "";           // 单个权限
  5.     String[] all() default {};            // 全部权限(AND)
  6.     String[] any() default {};            // 任意权限(OR)
  7.     String role() default "";              // 单个角色
  8.     String message() default "权限不足";   // 错误消息
  9. }
复制代码
AOP切面


  • 拦截 @RequirePermission 注解的方法
  • 从PermissionContext获取用户信息
  • 调用PermissionValidator验证权限
  • 验证失败抛出异常
  1. 1 @Aspect
  2. 2 public class PermissionAspect {
  3. 3     
  4. 4     @Before("@annotation(RequirePermission)")
  5. 5     public void checkPermission(JoinPoint joinPoint) {
  6. 6         RequirePermission annotation = getAnnotation(joinPoint);
  7. 7         
  8. 8         // 验证权限
  9. 9         if (!permissionValidator.hasPermission(annotation.value())) {
  10. 10             throw new PermissionDeniedException(annotation.message());
  11. 11         }
  12. 12     }
  13. 13 }
复制代码
与SpringBoot项目集成

配置类设计


  • 自动配置各个组件
  • 支持条件装配(@ConditionalOnMissingBean)
  • 提供默认实现
  1. 1 @Configuration
  2. 2 @EnableConfigurationProperties(PermissionProperties.class)
  3. 3 public class PermissionAutoConfiguration {
  4. 4     
  5. 5     @Bean
  6. 6     @ConditionalOnMissingBean
  7. 7     public PermissionMatcher permissionMatcher() {
  8. 8         return new WildcardPermissionMatcher();
  9. 9     }
  10. 10     
  11. 11     @Bean
  12. 12     @ConditionalOnMissingBean
  13. 13     public PermissionValidator permissionValidator(PermissionMatcher matcher) {
  14. 14         return new DefaultPermissionValidator(matcher);
  15. 15     }
  16. 16     
  17. 17     @Bean
  18. 18     @ConditionalOnMissingBean
  19. 19     public PermissionFilter permissionFilter(...) {
  20. 20         return new PermissionFilter(...);
  21. 21     }
  22. 22 }
复制代码
使用示例:
  1. 1 @RestController
  2. 2 @RequestMapping("/api/user")
  3. 3 public class UserController {
  4. 4     
  5. 5     // 单个权限验证
  6. 6     @GetMapping("/list")
  7. 7     @RequirePermission("sys:user:list")
  8. 8     public ResponseEntity<List<User>> list() {
  9. 9         return ResponseEntity.ok(userService.list());
  10. 10     }
  11. 11     
  12. 12     // 多个权限(全部满足)
  13. 13     @PutMapping("/{id}")
  14. 14     @RequirePermission(all = {"sys:user:update", "sys:user:edit"})
  15. 15     public ResponseEntity<Void> update(@PathVariable Long id, @RequestBody User user) {
  16. 16         userService.update(id, user);
  17. 17         return ResponseEntity.ok().build();
  18. 18     }
  19. 19     
  20. 20     // 多个权限(任意一个)
  21. 21     @DeleteMapping("/{id}")
  22. 22     @RequirePermission(any = {"sys:user:delete", "sys:user:remove"})
  23. 23     public ResponseEntity<Void> delete(@PathVariable Long id) {
  24. 24         userService.delete(id);
  25. 25         return ResponseEntity.ok().build();
  26. 26     }
  27. 27     
  28. 28     // 角色验证
  29. 29     @GetMapping("/admin")
  30. 30     @RequirePermission(role = "ADMIN")
  31. 31     public ResponseEntity<String> adminOnly() {
  32. 32         return ResponseEntity.ok("Admin only");
  33. 33     }
  34. 34 }
复制代码
  1. 1 @Service
  2. 2 public class UserService {
  3. 3     
  4. 4     @Autowired
  5. 5     private PermissionValidator permissionValidator;
  6. 6     
  7. 7     public void deleteUser(Long userId) {
  8. 8         
  9. 9         if (!permissionValidator.hasPermission("sys:user:delete")) {
  10. 10             throw new PermissionDeniedException("无删除权限");
  11. 11         }
  12. 12         
  13. 13         userRepository.delete(userId);
  14. 14     }
  15. 15     
  16. 16     public UserContext getCurrentUser() {
  17. 17         return permissionValidator.getCurrentUser();
  18. 18     }
  19. 19 }
复制代码
总结:


  • 接口抽象:所有核心功能都通过接口定义,便于扩展
  • 分层设计:Provider → Storage → Matcher → Validator,职责清晰
  • 上下文管理:使用ThreadLocal,支持异步场景
  • 配置化:SQL、路径等可配置,适应不同项目
  • 默认实现:提供常用实现,开箱即用
按照以上设计思路,可实现一个灵活易用的权限控制框架。
 
 
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册