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

news/2026/1/27 10:47:46/文章来源:https://www.cnblogs.com/Marktowin/p/19536935

前一篇已经分析了多种权限模型控制权限系列之(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.mzph.cn/news/1223649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我猜,不止200万台。拓竹2025年到底卖了多少台3D打印机?

是145万、200万&#xff0c;还是340万台&#xff1f;我们不妨从一组数据说起。根据公开数据显示&#xff0c;2025年我国累计出口了503万台3D打印机&#xff0c;同比增长33.2%。而出口总额也达到了113.54亿元&#xff0c;同比增长39.1%&#xff0c;首次突破百亿元大关。回顾2024…

【Django毕设源码分享】Django的基于web的共青团员信息管理系统的设计与实现的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

PHP日志格式 = json格式?

PHP 日志格式 ≠ JSON 格式 —— 二者是 可选关系&#xff0c;而非等同关系。 传统 PHP 日志&#xff1a;纯文本&#xff08;如 error_log、Monolog 默认格式&#xff09;JSON 日志&#xff1a;结构化日志的一种可选格式&#xff0c;需显式配置 是否使用 JSON 取决于 日志消费…

新疆体育用品品牌企业怎么选,聚焦诚信品牌

在数字化浪潮席卷各行业的当下,体育用品行业的品牌力与技术实力愈发依赖线上展示与服务能力,一个能彰显专业度与科技感的平台,是企业在市场竞争中脱颖而出的关键。面对市场上众多体育用品品牌企业,如何抉择?以下依…

说说全国楼梯贴批量定制,江苏美达自粘材料靠谱吗

很多客户在找楼梯贴批量定制的合作方时,都会遇到这样的问题:供应商能否快速响应大规模订单需求?产品质量是否稳定?交付周期能否保障?作为自粘装饰材料领域的优质供应商,江苏美达自粘材料有限公司凭借10万平方米的…

您是否也遭遇产品防腐性价比低的困扰,2026年江苏水分活度仪推荐

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家在水分活度仪领域的标杆企业,为食品、饲料、检测等行业企业选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:无锡市华科仪器仪表有限公司 推荐指…

2026年高性价比UPS电源代理供应商排名,金盛通科技表现亮眼

在数字化时代,电力保障是企业IT系统稳定运行的基石,而UPS电源作为关键物理基础设施的核心组件,其代理商的选择直接关系到企业供电安全与运维效率。面对市场上琳琅满目的UPS电源代理商,如何挑选出专业可靠的合作伙伴…

PPR给水管节能型厂家都得利管业产品性价比高不高

在塑料管道领域,如何选择专业的PPR给水管厂家是众多工程方和经销商的核心关注点,毕竟PPR给水管直接关系到供水系统的安全与寿命。四川都得利管业有限公司作为深耕行业17年的专业企业,在PPR给水管的生产、研发和服务…

解读口碑好的玻璃温室制造商,冠丰温室费用贵吗?

随着现代化农业的快速发展,玻璃温室作为高效农业设施的核心载体,其建造质量直接影响种植效率与作物品质。然而,市场上玻璃温室建造厂商鱼龙混杂,许多农业生产者在选择时面临找不到专业厂家、造价虚高、质量无保障等…

云服务器CVM 云主机 云计算服务器 弹性云服务器-腾讯云

云服务器CVM概述腾讯云服务器CVM&#xff08;Cloud Virtual Machine&#xff09;是一种弹性计算服务&#xff0c;提供可扩展的虚拟化计算资源。用户无需购买物理硬件&#xff0c;即可快速部署应用&#xff0c;支持按需付费和灵活配置。CVM适用于Web应用、大数据分析、游戏服务等…

云服务器哪家好用又实惠?一文读懂四大实惠云服务商深度解析

云服务器性价比对比&#xff1a;四大主流服务商解析选择云服务器时&#xff0c;需综合考虑性能、价格、稳定性及售后服务。以下对阿里云、腾讯云、华为云和AWS&#xff08;亚马逊云&#xff09;四大服务商进行深度对比&#xff0c;涵盖适用场景、价格策略及核心优势。阿里云&am…

分享经济视角下社会化众包与众筹的创新路径——链动2+1模式AI智能名片小程序的融合应用

摘要&#xff1a;在数字经济快速迭代的背景下&#xff0c;分享经济思维推动社会化众包与众筹模式成为企业资源整合、资金筹集及运营效率提升的核心抓手。社会化众包通过汇聚分散社会力量完成专业化任务&#xff0c;众筹则依托大众参与实现资金与资源的快速聚合&#xff0c;两者…

【瑞芯微平台实时Linux方案系列】第二篇 - 瑞芯微芯片PREEMPT_RT补丁集成与内核移植

一、简介&#xff1a;为什么是PREEMPT_RT 瑞芯微&#xff1f; 市场背景&#xff1a; 边缘视觉&#xff08;缺陷检测、人脸识别&#xff09;要求帧到帧延迟≤30ms&#xff0c;抖动<5ms&#xff1b; 工业机器人对伺服环≤1ms&#xff0c;传统Linux调度无法满足。 芯片选型…

骑行,说说各职业骑友的可爱特点。

骑友不问职业&#xff0c;但每个职业骑友都有各自的特点&#xff0c;这也是一个骑行的风景线。我们车队里什么人都有。程序员、老师、开小超市的、搞装修的。白天大家在各忙各的&#xff0c;晚上或周末聚在一起&#xff0c;就只有一个身份&#xff0c;骑车的。职业会悄悄改变你…

让Agent画思维导图稳固长期记忆:新框架实现稳定长期学习,准确率提升38%

传统RAG在“长期记忆管理”和“持续学习承载能力”两个层面&#xff0c;正在同时暴露出结构性瓶颈。 思维导图曾被证明可以帮助学习障碍者快速提升成绩&#xff0c;那么当前已经可堪一用的智能体系统如果引入类似工具是否可以帮助改善长期学习记忆能力呢&#xff1f;有研究团队…

【通信原理】无线电台工作原理深度解析:从电磁波到信息传输的完整技术体系

第一章 无线电台的历史演进与现代应用 无线电的发现与应用是人类技术史上最伟大的成就之一。1887年&#xff0c;德国物理学家赫兹首次证实了电磁波的存在&#xff0c;为现代无线通信奠定了理论基础。随后&#xff0c;意大利工程师马可尼在1895年实现了第一次远距离无线电通信&…

NMN启动细胞焕新计划,W+端粒塔研创NMN十二载,带领抗衰进入健康管理2.0时代

今年年货节,年轻人的购物车里不只有食品和潮品,更有各式保健品。当抗衰老从小众需求升级为全民共识,以预防为主的核心诉求催生了庞大的保健市场需求,一场关于健康与爱的消费热潮在年末得到集中释放。这背后,折射出…

法国用工“雷区”遍布?EOR成中企出海“合规导航仪”

法国,这个拥有浪漫之都巴黎的国度,也是全球劳动法最严格的国家之一。面对其严苛的用工规定,许多出海企业望而却步。 法国作为欧洲第二大经济体,拥有庞大的消费市场和成熟的商业环境,吸引了众多科技、制造及跨境电…

医用导管哪家好?宁波益创韦如何在高精度管材赛道脱颖而出

在介入治疗、麻醉呼吸、监护输注等临床场景中,医用导管早已成为基础却关键的组成部分。医院在选择合作供应商时,不再只问“能不能做”,而是越来越关注尺寸精度、材料安全、供应稳定性等综合指标,“医用导管哪家好”…

Logback、Log4j2、SLF4J 、ELK、EFK、Loki 傻傻分不清楚?

前言 今天我想和大家聊聊一个看似基础,却让无数开发者困惑的问题:日志框架这么多,它们到底是什么关系? Logback、Log4j2、SLF4J、ELK、EFK、Loki……这些名词像是一锅粥,很多人用了多年仍分不清彼此。 有些小伙伴…