RBAC模型

常见的权限控制模型主要有三种:

  1. 粗粒度控制(硬编码)

    比如直接在接口里写 if 判断某个用户 ID 或角色字符串,这种方式简单但不易维护,扩展性差。

  2. ACL(Access Control List)访问控制列表

    给每个用户分配具体权限,权限控制到“用户-资源”级别,灵活但不易管理,尤其是用户多、权限复杂时维护成本非常高。

  3. RBAC(Role-Based Access Control)角色权限控制

    用户 → 拥有角色,角色 → 拥有权限,权限再映射到资源或操作。抽象出“角色”作为中间层,复用性更高,也便于后台配置和系统扩展

为什么选择 RBAC?

我这个项目有普通用户、VIP 用户、管理员三类身份,不同角色对应不同权限。为了做到权限清晰、可配置、易维护,我选择了 RBAC。

RBAC 的优势在于:

  • 权限配置集中、统一,不会分散在代码中;
  • 不同角色对应不同操作权限,修改角色就能控制一批权限
  • 后台可以实现可视化的权限管理,甚至后期接入前端菜单动态生成都更方便。

我的 RBAC 实现方式(3张主表 + 2张关联表)

在数据库中我设计了五张表:

  • user 用户表
  • role 角色表
  • permission 权限表
  • user_role 用户-角色关联表
  • role_permission 角色-权限关联表

每个用户可以有多个角色,每个角色对应多个权限,这样结构上可以灵活扩展。

在权限校验上,我是通过 注解 + 拦截器 的方式实现的,整体逻辑如下:

每当用户访问接口时,我的拦截器会在方法执行前先做一层权限判断。

✅ 第一步:获取注解内容

拦截器通过反射拿到当前方法上的注解,比如:

  • @PreAuthorize("system:user:edit")
  • @PreAuthorizeRole("ADMIN")

我会先判断这个接口要求的具体权限点角色身份是什么。


✅ 第二步:获取用户登录态

然后我会从 Redis 中根据 Token 拿到当前登录用户的信息。这个信息在用户登录时就已经缓存了,包括:

  • 用户 ID
  • 拥有的角色列表(比如:["USER", "VIP"])

✅ 第三步:角色 → 权限展开

接下来,我会从 Redis 中根据这些角色,查出该用户所有的权限集合。

  • 这里权限和角色是多对多关系,用户拥有多个角色,每个角色对应多个权限;
  • 所以我会做一次权限合并 + 去重操作,拿到这个用户最终的权限全集;
  • 最后判断注解里要求的权限是否在这个集合中。

这套逻辑相比在代码里写 if 判断角色或者 userId 更加清晰统一,权限声明与业务逻辑解耦,而且我在注解拦截逻辑里还预留了日志记录点,后续可以统计权限命中率或者审计操作日志。