当前位置: 首页 > news >正文

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

前一篇已经分析了多种权限模型控制权限系列之(1)模型分析梳理,其中比较常用的是基于角色的权限控制。

基于角色的权限控制的表设计:

用户表
角色表
菜单表用户--角色关系表
角色--菜单关系表

权限标识格式:

格式:xxx:xxx:xxx(模块:资源:操作)

权限架构的分层结构:

应用层 (@RequirePermission注解)↓
权限验证层 (PermissionValidator)↓
权限上下文层 (PermissionContext - ThreadLocal)↓
权限提供层 (PermissionProvider - 数据库/缓存)↓
权限存储层 (PermissionStorage - Redis/Memory)

权限架构接口:

权限提供者接口 (PermissionProvider)

从数据源获取用户权限数据

 1 public interface PermissionProvider {
 2     // 获取用户的所有权限标识
 3     Set<String> getUserPermissions(Object userId);
 4     
 5     // 获取用户角色列表
 6     Set<String> getUserRoles(Object userId);
 7     
 8     // 检查用户是否为超级管理员
 9     boolean isSuperAdmin(Object userId);
10     
11     // 刷新用户权限缓存
12     void refreshUserPermissions(Object userId);
13 }
  • userId 使用 Object 类型,支持 String、Long 等不同ID类型
  • 支持超级管理员逻辑(拥有所有权限)
  • 提供刷新接口,支持权限变更后更新缓存

权限存储接口 (PermissionStorage)

权限数据的存储和读取(Token、Redis、Memory等)

 1 public interface PermissionStorage {
 2     // 存储用户权限信息
 3     void storeUserInfo(String token, UserInfo userInfo);
 4     
 5     // 获取用户权限信息
 6     UserInfo getUserInfo(String token);
 7     
 8     // 删除用户权限信息
 9     void removeUserInfo(String token);
10     
11     // 刷新用户权限信息
12     void refreshUserInfo(String token, UserInfo userInfo);
13 }
  • 基于Token存储,支持分布式场景
  • 支持多种存储实现(Redis、Memory、数据库等)
  • 提供刷新接口,支持权限实时更新

权限匹配器接口 (PermissionMatcher)

权限匹配策略(精确匹配、通配符匹配等)

 1 public interface PermissionMatcher {
 2     // 匹配权限
 3     boolean match(String requiredPermission, Set<String> userPermissions);
 4     
 5     // 批量匹配(全部满足)
 6     boolean matchAll(Set<String> requiredPermissions, Set<String> userPermissions);
 7     
 8     // 批量匹配(任意一个满足)
 9     boolean matchAny(Set<String> requiredPermissions, Set<String> userPermissions);
10 }
  • 支持多种匹配策略(精确、通配符、正则等)
  • 支持批量匹配(AND/OR逻辑)
  • 可扩展自定义匹配规则

用户信息

1 public class UserInfo {
2     private Object userId;                    // 用户ID
3     private String username;                  // 用户名
4     private Set<String> permissions;          // 权限集合
5     private Set<String> roles;                // 角色集合
6     private boolean superAdmin;               // 是否超级管理员
7     private Map<String, Object> attributes;   // 扩展属性
8 }
  • 使用 Object 类型支持不同ID类型
  • 提供扩展属性,支持业务字段存储
  • 轻量级设计,便于序列化和传输

权限上下文 (PermissionContext)

基于ThreadLocal的权限上下文管理

 1 public class PermissionContext {
 2     private static final ThreadLocal<UserInfo> USER_INFO_HOLDER = new TransmittableThreadLocal<>();
 4     
 5     public static void set(UserInfo userInfo);
 6     public static UserInfo get();
 7     public static void clear();
 8     
 9     public static boolean hasPermission(String permission);
10     public static Set<String> getPermissions();
11 }
  • 使用 TransmittableThreadLocal 支持线程池传递
  • 提供便捷方法,简化权限判断
  • 请求结束后自动清理,避免内存泄漏

权限验证器接口 (PermissionValidator)

权限验证逻辑

 1 public interface PermissionValidator {
 2     // 验证单个权限
 3     boolean hasPermission(String permission);
 4     
 5     // 验证所有权限(AND)
 6     boolean hasAllPermissions(Set<String> permissions);
 7     
 8     // 验证任意权限(OR)
 9     boolean hasAnyPermission(Set<String> permissions);
10     
11     // 验证角色
12     boolean hasRole(String role);
13     
14     // 获取当前用户上下文
15     UserContext getCurrentUser();
16 }
  • 提供多种验证方式(单个、全部、任意)
  • 支持角色验证
  • 统一权限验证入口

实现策略

数据库权限获取

  1. 通过JdbcTemplate执行SQL查询
  2. SQL可配置化(支持不同数据库表结构)
  3. 支持超级管理员特殊处理
  4. 支持权限缓存
 1 @Component
 2 public class DatabasePermissionProvider implements PermissionProvider {
 3     
 4     @Override
 5     public Set<String> getUserPermissions(Object userId) {
 6         // 1. 检查是否为超级管理员
 7         if (isSuperAdmin(userId)) {
 8             return getAllPermissions(); // 返回所有权限
 9         }
10         
11         // 2. 查询用户权限(通过用户-角色-菜单关联)
12         List<String> permsList =userService.getPermissions();19         
20         // 3. 返回权限集合
21         return permsList;
27     }
28 }

抽象权限提供者 (AbstractPermissionProvider)

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

Redis存储 (RedisPermissionStorage)

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

通配符匹配器 (WildcardPermissionMatcher)

  • 支持 * 和 ? 通配符
  • 例如:sys:user:* 匹配 sys:user:savesys:user:update 等
  • 使用Spring的 PatternMatchUtils.simpleMatch()

权限过滤器实现

  1. 请求头提取Token
  2. 从Storage获取用户信息(如不存在,从Provider加载)
  3. 设置到PermissionContext
  4. 请求结束后清理上下文
过滤器流程:

请求到达↓ 检查排除路径(登录、公开接口等)↓ 提取Token↓ 从Storage获取用户信息↓(如果不存在) 从Provider加载用户信息 → 存储到Storage↓ 设置到PermissionContext↓ 继续请求处理↓ 清理PermissionContext

权限注解 (@RequirePermission)

  • 支持单个权限、多个权限(AND/OR)
  • 支持角色验证
  • 支持自定义错误消息
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {String value() default "";           // 单个权限String[] all() default {};            // 全部权限(AND)String[] any() default {};            // 任意权限(OR)String role() default "";              // 单个角色String message() default "权限不足";   // 错误消息
}

AOP切面实现

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

与SpringBoot项目集成

配置类设计

  • 自动配置各个组件
  • 支持条件装配(@ConditionalOnMissingBean)
  • 提供默认实现
 1 @Configuration
 2 @EnableConfigurationProperties(PermissionProperties.class)
 3 public class PermissionAutoConfiguration {
 4     
 5     @Bean
 6     @ConditionalOnMissingBean
 7     public PermissionMatcher permissionMatcher() {
 8         return new WildcardPermissionMatcher(); 
 9     }
10     
11     @Bean
12     @ConditionalOnMissingBean
13     public PermissionValidator permissionValidator(PermissionMatcher matcher) {
14         return new DefaultPermissionValidator(matcher);
15     }
16     
17     @Bean
18     @ConditionalOnMissingBean
19     public PermissionFilter permissionFilter(...) {
20         return new PermissionFilter(...);
21     }
22 }

使用示例:

 1 @RestController
 2 @RequestMapping("/api/user")
 3 public class UserController {
 4     
 5     // 单个权限验证
 6     @GetMapping("/list")
 7     @RequirePermission("sys:user:list")
 8     public ResponseEntity<List<User>> list() {
 9         return ResponseEntity.ok(userService.list());
10     }
11     
12     // 多个权限(全部满足)
13     @PutMapping("/{id}")
14     @RequirePermission(all = {"sys:user:update", "sys:user:edit"})
15     public ResponseEntity<Void> update(@PathVariable Long id, @RequestBody User user) {
16         userService.update(id, user);
17         return ResponseEntity.ok().build();
18     }
19     
20     // 多个权限(任意一个)
21     @DeleteMapping("/{id}")
22     @RequirePermission(any = {"sys:user:delete", "sys:user:remove"})
23     public ResponseEntity<Void> delete(@PathVariable Long id) {
24         userService.delete(id);
25         return ResponseEntity.ok().build();
26     }
27     
28     // 角色验证
29     @GetMapping("/admin")
30     @RequirePermission(role = "ADMIN")
31     public ResponseEntity<String> adminOnly() {
32         return ResponseEntity.ok("Admin only");
33     }
34 }

代码逻辑使用:

 1 @Service
 2 public class UserService {
 3     
 4     @Autowired
 5     private PermissionValidator permissionValidator;
 6     
 7     public void deleteUser(Long userId) {
 8         
 9         if (!permissionValidator.hasPermission("sys:user:delete")) {
10             throw new PermissionDeniedException("无删除权限");
11         }
12         
13         userRepository.delete(userId);
14     }
15     
16     public UserContext getCurrentUser() {
17         return permissionValidator.getCurrentUser();
18     }
19 }

 

总结:

  1. 接口抽象:所有核心功能都通过接口定义,便于扩展
  2. 分层设计:Provider → Storage → Matcher → Validator,职责清晰
  3. 上下文管理:使用ThreadLocal,支持异步场景
  4. 配置化:SQL、路径等可配置,适应不同项目
  5. 默认实现:提供常用实现,开箱即用

按照以上设计思路,可以逐步实现一个通用、灵活、易用的权限控制框架。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

http://www.jsqmd.com/news/307457/

相关文章:

  • 我猜,不止200万台。拓竹2025年到底卖了多少台3D打印机?
  • 【Django毕设源码分享】Django的基于web的共青团员信息管理系统的设计与实现的设计与实现(程序+文档+代码讲解+一条龙定制)
  • PHP日志格式 = json格式?
  • 新疆体育用品品牌企业怎么选,聚焦诚信品牌
  • 说说全国楼梯贴批量定制,江苏美达自粘材料靠谱吗
  • 您是否也遭遇产品防腐性价比低的困扰,2026年江苏水分活度仪推荐
  • 2026年高性价比UPS电源代理供应商排名,金盛通科技表现亮眼
  • PPR给水管节能型厂家都得利管业产品性价比高不高
  • 解读口碑好的玻璃温室制造商,冠丰温室费用贵吗?
  • 云服务器CVM 云主机 云计算服务器 弹性云服务器-腾讯云
  • 云服务器哪家好用又实惠?一文读懂四大实惠云服务商深度解析
  • 分享经济视角下社会化众包与众筹的创新路径——链动2+1模式AI智能名片小程序的融合应用
  • 【瑞芯微平台实时Linux方案系列】第二篇 - 瑞芯微芯片PREEMPT_RT补丁集成与内核移植
  • 骑行,说说各职业骑友的可爱特点。
  • 让Agent画思维导图稳固长期记忆:新框架实现稳定长期学习,准确率提升38%
  • 【通信原理】无线电台工作原理深度解析:从电磁波到信息传输的完整技术体系
  • NMN启动细胞焕新计划,W+端粒塔研创NMN十二载,带领抗衰进入健康管理2.0时代
  • 法国用工“雷区”遍布?EOR成中企出海“合规导航仪”
  • 医用导管哪家好?宁波益创韦如何在高精度管材赛道脱颖而出
  • Logback、Log4j2、SLF4J 、ELK、EFK、Loki 傻傻分不清楚?
  • python lambda匿名函数
  • 导师推荐!8个AI论文平台测评,本科生毕业论文全攻略
  • 什么是google算法?搞懂底层逻辑才不会被收割
  • 汽车行业如何突围?天淳AI+GEO精准获客新策略
  • 学霸同款2026 AI论文平台TOP8:研究生开题报告神器测评
  • VSCode中,通过SFTP插件管理远程服务器文件
  • 2025年棕刚玉十大定制品牌口碑排行榜,棕刚玉/碳化硅/黑碳化硅/磨料/金刚砂/铬刚玉/不锈钢灰/精密铸造砂/白刚玉棕刚玉品牌有哪些
  • Windows10聚焦图片保存位置说明
  • 当八股文遇到实践--关于StringBuilder 和String
  • 想要随时随地做账务自动化任务就用青龙面板+cpolar