一、什么是 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 和权限缓存

Comments NOTHING