RBAC模型相关知识

Sylphia 发布于 19 天前 56 次阅读


一、什么是 RBAC?

RBAC 全称是 Role-Based Access Control,中文一般叫“基于角色的访问控制”。

简单理解就是:系统不直接给用户分配权限,而是先创建角色,再给角色分配权限,最后把用户绑定到角色上。

比如一个后台管理系统里,有管理员、普通员工、财务人员、审核人员等角色。不同角色能看到的菜单、能操作的按钮、能访问的接口都不一样,这就是典型的 RBAC 权限模型。

RBAC 的核心思想可以概括为:

用户 → 角色 → 权限

也就是说,用户拥有什么权限,取决于他拥有哪些角色。

二、为什么需要 RBAC?

如果系统比较简单,可能直接判断用户 ID 或用户类型就能控制权限。但是当系统越来越复杂,用户越来越多,权限越来越细时,直接给每个用户分配权限就会非常混乱。

比如系统有 100 个用户、50 个权限,如果每个用户单独配置权限,维护成本会非常高。用户岗位变动时,还需要一个个调整权限,容易出错。

使用 RBAC 后,只需要维护角色和权限的关系,再把用户分配到合适的角色即可。这样权限管理会更清晰,也更容易维护。

RBAC 主要解决的问题包括:

  • 降低权限维护成本
  • 避免用户权限配置混乱
  • 方便根据岗位分配权限
  • 方便控制菜单、按钮、接口访问
  • 提高系统安全性和可维护性

三、RBAC 的核心概念

1. 用户

用户就是系统中的登录账号,比如后台管理员、普通员工、部门负责人等。

用户本身一般不直接保存具体权限,而是通过角色间接获得权限。

用户:张三
角色:管理员
权限:用户管理、角色管理、菜单管理、数据统计

2. 角色

角色可以理解为一组权限的集合。它通常对应现实中的岗位或身份。

常见角色包括:

  • 超级管理员
  • 系统管理员
  • 普通用户
  • 财务人员
  • 审核人员
  • 部门负责人

角色的作用是承上启下:用户绑定角色,角色绑定权限。

用户 → 角色
角色 → 权限

3. 权限

权限表示用户可以做什么。权限可以分为菜单权限、按钮权限、接口权限、数据权限等。

例如:

  • 查看用户列表
  • 新增用户
  • 编辑用户
  • 删除用户
  • 导出数据
  • 审核申请

在实际系统中,权限通常会用一个权限标识来表示。

system:user:list
system:user:add
system:user:edit
system:user:delete
system:role:list
system:menu:list

后端接口就可以根据这些权限标识来判断当前用户是否有操作权限。

四、RBAC 常见的数据表设计

一个基础的 RBAC 权限系统,通常至少需要五张表:

表名说明
sys_user用户表
sys_role角色表
sys_permission权限表,也可以叫菜单表
sys_user_role用户角色关联表
sys_role_permission角色权限关联表

它们之间的关系是:

用户表 sys_user
    ↓
用户角色关联表 sys_user_role
    ↓
角色表 sys_role
    ↓
角色权限关联表 sys_role_permission
    ↓
权限表 sys_permission

1. 用户表

sys_user
- id
- username
- password
- nickname
- phone
- status
- create_time
- update_time

用户表主要保存登录账号相关信息,比如用户名、密码、手机号、状态等。

2. 角色表

sys_role
- id
- role_name
- role_code
- status
- create_time
- update_time

角色表保存系统中的角色信息。

role_name:管理员
role_code:admin

role_code 一般用于代码中判断角色,比如判断当前用户是否为管理员。

3. 权限表

sys_permission
- id
- parent_id
- permission_name
- permission_code
- permission_type
- path
- component
- icon
- sort
- status
- create_time
- update_time

权限表既可以保存菜单,也可以保存按钮权限。很多后台系统会把菜单和按钮都放在同一张表里,通过 permission_type 字段区分。

permission_type = M 表示目录
permission_type = C 表示菜单
permission_type = B 表示按钮

例如:

用户管理:system:user
用户查询:system:user:list
用户新增:system:user:add
用户修改:system:user:edit
用户删除:system:user:delete

4. 用户角色关联表

sys_user_role
- id
- user_id
- role_id

用户和角色通常是多对多关系。一个用户可以拥有多个角色,一个角色也可以分配给多个用户。

张三 → 管理员
李四 → 普通用户
王五 → 财务人员、审核人员

5. 角色权限关联表

sys_role_permission
- id
- role_id
- permission_id

角色和权限也是多对多关系。一个角色可以拥有多个权限,一个权限也可以分配给多个角色。

管理员 → 用户管理、角色管理、菜单管理
普通用户 → 个人信息查看
财务人员 → 财务报表、数据导出

五、RBAC 的权限校验流程

用户登录系统后,后端通常会根据用户 ID 查询用户拥有的角色和权限,然后把权限信息返回给前端,或者存入缓存中。

一个常见的权限校验流程如下:

1. 用户登录
2. 后端校验用户名和密码
3. 登录成功后生成 Token
4. 根据用户 ID 查询角色列表
5. 根据角色 ID 查询权限列表
6. 将用户信息和权限信息返回给前端
7. 前端根据权限生成动态菜单
8. 用户访问接口时,后端再次校验权限

需要注意的是,前端控制菜单显示只是为了用户体验,真正的权限安全必须由后端控制。

也就是说,不能只靠前端隐藏按钮。因为用户可以通过浏览器开发者工具、Postman 或其他方式直接请求后端接口。如果后端不做权限校验,接口仍然可能被非法访问。

六、菜单权限和按钮权限

1. 菜单权限

菜单权限主要控制用户登录系统后能看到哪些菜单。

比如管理员可以看到:

  • 首页
  • 用户管理
  • 角色管理
  • 菜单管理
  • 系统设置

普通用户可能只能看到:

  • 首页
  • 个人中心

前端一般会根据后端返回的菜单树动态生成路由。

后端返回菜单树 → 前端生成动态路由 → 页面显示对应菜单

2. 按钮权限

按钮权限主要控制用户在页面中能不能看到某些操作按钮。

比如用户管理页面中可能有这些按钮:

  • 新增
  • 编辑
  • 删除
  • 导入
  • 导出

不同角色拥有的按钮权限不一样。普通用户可能只能查看,管理员才可以新增、编辑、删除。

system:user:add     新增用户
system:user:edit    编辑用户
system:user:delete  删除用户
system:user:export  导出用户

前端可以根据权限标识判断是否展示按钮,后端则根据权限标识判断接口是否允许访问。

七、接口权限控制

接口权限控制是 RBAC 中非常重要的一部分。前端隐藏按钮并不能保证安全,后端接口必须再次校验。

在 Java 后端项目中,常见做法是在接口上加权限注解。

@PreAuthorize("hasAuthority('system:user:add')")
@PostMapping("/user/add")
public Result addUser(@RequestBody User user) {
    return userService.addUser(user);
}

这段代码表示:只有拥有 system:user:add 权限的用户,才能访问新增用户接口。

八、数据权限

除了菜单权限、按钮权限和接口权限,实际项目中还经常会遇到数据权限。

数据权限控制的是:用户可以看到哪些数据。

比如在一个企业管理系统中:

  • 普通员工只能查看自己的数据
  • 部门负责人可以查看本部门的数据
  • 公司领导可以查看全公司的数据
  • 超级管理员可以查看所有数据

菜单权限控制的是“能不能进入页面”,按钮权限控制的是“能不能点击操作”,数据权限控制的是“能看到哪些数据”。

菜单权限:能不能看用户管理菜单
按钮权限:能不能点删除按钮
接口权限:能不能访问删除接口
数据权限:能不能操作这个部门的数据

数据权限通常会结合部门 ID、用户 ID、角色类型等字段实现。

超级管理员:查询全部数据
部门负责人:查询本部门及下级部门数据
普通用户:只查询本人数据

九、RBAC 在项目中的常见实现方式

在 Java 后端项目中,RBAC 通常会和 Spring Security、Sa-Token、Shiro 或自定义拦截器结合使用。

1. Spring Security

Spring Security 功能比较完整,适合中大型项目。它可以处理登录认证、权限校验、接口拦截、密码加密、Token 认证等功能。

常见权限注解包括:

@PreAuthorize
@PostAuthorize
@Secured

例如:

@PreAuthorize("hasAuthority('system:role:list')")
@GetMapping("/role/list")
public Result roleList() {
    return roleService.list();
}

2. Sa-Token

Sa-Token 是国内项目中比较常见的轻量级权限认证框架,使用起来比 Spring Security 简单一些。

常见写法如下:

@SaCheckPermission("system:user:add")
@PostMapping("/user/add")
public Result addUser(@RequestBody User user) {
    return userService.addUser(user);
}

它表示当前用户必须拥有 system:user:add 权限,才能访问这个接口。

3. 自定义拦截器

如果项目比较简单,也可以通过自定义拦截器实现权限校验。

基本思路是:

1. 请求进入系统
2. 拦截器获取 Token
3. 根据 Token 获取用户信息
4. 查询用户权限
5. 判断当前接口是否需要权限
6. 如果有权限则放行
7. 如果没有权限则返回 403

自定义拦截器灵活性高,但需要自己处理很多细节,比如白名单、权限缓存、异常返回、Token 过期等问题。

十、RBAC 的权限缓存

如果每次请求接口都去数据库查询用户权限,会增加数据库压力。因此实际项目中通常会把用户权限缓存到 Redis 中。

常见做法是:

用户登录成功后:
1. 查询用户角色和权限
2. 将权限列表存入 Redis
3. 设置合理的过期时间

用户访问接口时:
1. 从 Token 中获取用户 ID
2. 根据用户 ID 从 Redis 查询权限
3. 判断是否拥有当前接口权限

这样可以减少数据库查询,提高接口响应速度。

但是使用权限缓存时要注意权限变更问题。如果管理员修改了某个用户的角色或权限,需要及时清理该用户的权限缓存,否则用户可能仍然使用旧权限。

修改用户角色后 → 删除该用户权限缓存
修改角色权限后 → 删除该角色下所有用户的权限缓存
用户退出登录后 → 删除该用户 Token 和权限缓存
此作者没有提供个人介绍。
最后更新于 2026-07-07