Skip to content

Database design permission


平台权限系统的设计需以RBAC(基于角色的访问控制)为核心,并扩展数据级权限能力(解决 “能看什么数据” 的问题),同时兼顾功能级权限(解决 “能做什么操作” 的问题)。以下是包含数据库表设计核心接口设计权限校验逻辑的完整平台权限系统设计方案,适用于中大型企业级平台(如 SaaS、管理后台、多租户系统)。

一、核心权限模型选型

平台权限系统优先选择 RBAC3(RBAC 的扩展模型)+ 数据权限 的组合方案:

  • RBAC3:支持角色继承用户 - 权限直接关联角色互斥,解决纯 RBAC 角色膨胀的问题;
  • 数据权限:基于部门、租户、数据范围(全部 / 本人 / 本部门)实现精细化数据访问控制,是平台权限的核心补充。

整体权限关系链:用户 ←→ 角色 ←→ 功能权限 ←→ 资源,同时角色 ←→ 数据权限规则约束数据可见性。

二、数据库表设计

数据库表设计遵循第三范式,同时为性能做适度冗余,核心分为基础权限表资源表数据权限表扩展表(多租户 / 日志)。以下以 MySQL 为例,给出表结构及核心字段说明。

1. 基础权限表

(1)用户表(sys_user)

存储平台用户基础信息,关联用户所属部门 / 租户。

字段名 类型 主键 / 索引 说明 示例值
user_id bigint 主键 用户唯一标识 1001
username varchar(50) 唯一索引 登录账号(不可重复) admin
password varchar(100) 加密密码(MD5/SHA256 + 盐值) xxx(加密后)
real_name varchar(50) 用户真实姓名 张三
dept_id bigint 索引 所属部门 ID(关联部门表) 201
tenant_id bigint 索引 租户 ID(多租户平台必选) 1
status tinyint 状态(0 - 禁用,1 - 启用) 1
create_time datetime 创建时间 2025-12-23 10:00:00
update_time datetime 更新时间 2025-12-23 11:00:00

(2)角色表(sys_role)

存储平台角色定义,角色是权限的集合。

字段名 类型 主键 / 索引 说明 示例值
role_id bigint 主键 角色唯一标识 301
role_name varchar(50) 角色名称(如超级管理员) 系统管理员
role_code varchar(50) 唯一索引 角色编码(不可重复,用于权限判断) ADMIN
role_desc varchar(200) 角色描述 拥有平台全部权限
parent_id bigint 索引 父角色 ID(支持角色继承) 0(无父角色)
tenant_id bigint 索引 租户 ID(多租户隔离) 1
status tinyint 状态(0 - 禁用,1 - 启用) 1
create_time datetime 创建时间 2025-12-23 10:00:00

(3)权限表(sys_permission)

存储功能级权限,绑定具体的资源(如接口、按钮、菜单)。

字段名 类型 主键 / 索引 说明 示例值
perm_id bigint 主键 权限唯一标识 401
perm_name varchar(50) 权限名称 用户管理 - 新增
perm_code varchar(100) 唯一索引 权限编码(核心,用于校验) sys:user:add
resource_type tinyint 索引 资源类型(1 - 菜单,2 - 按钮,3 - 接口) 2
resource_id bigint 索引 关联资源表 ID(如菜单 ID / 接口 ID) 501
tenant_id bigint 索引 租户 ID 1
status tinyint 状态(0 - 禁用,1 - 启用) 1

(4)用户 - 角色关联表(sys_user_role)

用户与角色的多对多关联表(一个用户可拥有多个角色)。

字段名 类型 主键 / 索引 说明 示例值
user_role_id bigint 主键 关联 ID 601
user_id bigint 联合索引 用户 ID 1001
role_id bigint 联合索引 角色 ID 301
tenant_id bigint 索引 租户 ID 1

(5)角色 - 权限关联表(sys_role_permission)

角色与权限的多对多关联表(一个角色可包含多个权限)。

字段名 类型 主键 / 索引 说明 示例值
role_perm_id bigint 主键 关联 ID 701
role_id bigint 联合索引 角色 ID 301
perm_id bigint 联合索引 权限 ID 401
tenant_id bigint 索引 租户 ID 1

2. 资源表(sys_resource)

存储平台的资源实体(菜单、按钮、接口),权限最终绑定到资源上。

字段名 类型 主键 / 索引 说明 示例值
resource_id bigint 主键 资源唯一标识 501
resource_name varchar(50) 资源名称 用户管理菜单
resource_type tinyint 索引 资源类型(1 - 菜单,2 - 按钮,3 - 接口) 1
path varchar(200) 资源路径(菜单路由 / 接口 URL) /sys/user
component varchar(200) 前端组件路径(仅菜单) sys/user/List
parent_id bigint 索引 父资源 ID(如子菜单归属父菜单) 0(顶级菜单)
sort int 排序号(用于前端展示) 10
status tinyint 状态(0 - 禁用,1 - 启用) 1

3. 数据权限表(sys_data_permission)

存储角色的数据访问规则,解决 “能看什么数据” 的问题,是平台权限的核心扩展。

字段名 类型 主键 / 索引 说明 示例值
data_perm_id bigint 主键 数据权限唯一标识 801
role_id bigint 索引 关联角色 ID 301
resource_id bigint 索引 关联资源 ID(如用户管理接口) 501
data_scope tinyint 数据范围(1 - 全部,2 - 本人,3 - 本部门,4 - 指定部门) 3
dept_ids varchar(500) 指定部门 ID 集合(data_scope=4 时生效) 201,202
tenant_id bigint 索引 租户 ID 1

4. 扩展表(可选)

  • 部门表(sys_dept):存储组织架构,字段包括dept_iddept_nameparent_idsorttenant_id等;
  • 权限操作日志表(sys_perm_log):记录权限变更(如角色分配、权限修改),字段包括log_idoper_useroper_typeoper_contentoper_time等;
  • 租户表(sys_tenant):多租户平台必选,字段包括tenant_idtenant_nameexpire_timestatus等。

三、核心接口设计

接口遵循RESTful 风格,统一响应格式为{ "code": 200, "msg": "成功", "data": {} },其中code为状态码(200 成功,403 权限拒绝,500 服务器错误)。

1. 角色管理接口

负责角色的增删改查、权限分配。

接口名称 请求方式 接口路径 请求参数示例 响应数据示例
创建角色 POST /api/v1/role {"roleName": "运营专员", "roleCode": "OPERATOR", "roleDesc": "运营操作权限", "tenantId": 1} {"code": 200, "msg": "创建成功", "data": { "roleId": 302} }
删除角色 DELETE /api/v1/role/{roleId} 路径参数:roleId=302 {"code": 200, "msg": "删除成功"}
修改角色 PUT /api/v1/role/{roleId} {"roleName": "高级运营专员", "roleDesc": "高级运营操作权限"} {"code": 200, "msg": "修改成功"}
查询角色列表 GET /api/v1/role 分页参数:page=1&size=10&tenantId=1 { "code": 200, "data": { "list": [...], "total": 10 } }
角色分配权限 POST /api/v1/role/{roleId}/perm { "permIds": [401, 402, 403] } {"code": 200, "msg": "权限分配成功"}
查询角色权限 GET /api/v1/role/{roleId}/perm 路径参数:roleId=301 { "code": 200, "data": [ { "permId": 401, "permCode": "sys:user:add" }, ... ] }

2. 用户权限接口

负责用户的角色绑定、权限查询。

接口名称 请求方式 接口路径 请求参数示例 响应数据示例
用户绑定角色 POST /api/v1/user/{userId}/role { "roleIds": [301, 302] } {"code": 200, "msg": "角色绑定成功"}
解除用户角色 DELETE /api/v1/user/{userId}/role { "roleIds": [302] } {"code": 200, "msg": "角色解除成功"}
查询用户权限 GET /api/v1/user/{userId}/perm 路径参数:userId=1001 { "code": 200, "data": { "permCodes": ["sys:user:add", "sys:role:list"] } }
查询当前用户权限 GET /api/v1/user/current/perm 无(从 Token 获取当前用户 ID) { "code": 200, "data": { "permCodes": [...], "dataScope": 3 } }

3. 权限资源接口

负责资源(菜单、按钮、接口)的管理。

接口名称 请求方式 接口路径 请求参数示例 响应数据示例
新增资源 POST /api/v1/resource {"resourceName": "用户管理按钮", "resourceType": 2, "path": "/sys/user/add", "parentId": 501} { "code": 200, "data": { "resourceId": 502 } }
查询资源树 GET /api/v1/resource/tree 参数:resourceType=1(仅查菜单) { "code": 200, "data": [ { "resourceId": 501, "children": [...] }, ... ] }

4. 数据权限接口

负责数据权限规则的配置与查询。

接口名称 请求方式 接口路径 请求参数示例 响应数据示例
配置数据权限 POST /api/v1/data-perm { "roleId": 302, "resourceId": 501, "dataScope": 3, "deptIds": "201,202" } {"code": 200, "msg": "配置成功"}
查询角色数据权限 GET /api/v1/data-perm/role/{roleId} 路径参数:roleId=302 { "code": 200, "data": [ { "dataScope": 3, "deptIds": "201,202" }, ... ] }

四、权限校验实现

权限系统的核心是 “校验”,需覆盖前端按钮 / 菜单和**后端接口 / 数据 ** 两层校验。

1. 前端权限校验

  • 菜单权限:前端从/api/v1/user/current/perm获取当前用户的资源列表,根据resource_type=1(菜单)过滤出可展示的菜单,渲染路由;
  • 按钮权限:通过权限编码(如sys:user:add)判断按钮是否显示,示例(Vue 代码):

    <el-button v-if="hasPerm('sys:user:add')" type="primary">新增用户</el-button>
    <script>
    export default {
      methods: {
        hasPerm(permCode) {
          return this.userPerms.includes(permCode); // userPerms为当前用户的权限编码数组
        }
      }
    }
    </script>
    

2. 后端权限校验

  • 接口权限校验:通过拦截器 / AOP实现,步骤如下:

    1. 从 Token 中解析当前用户 ID,查询用户的权限编码列表;
    2. 解析接口对应的权限编码(如通过注解@RequiresPerm("sys:user:add"));
    3. 对比用户权限编码是否包含接口所需权限,不包含则返回 403。

      示例(Spring Boot 拦截器核心代码):

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取当前用户权限
        List<String> userPerms = SecurityUtils.getCurrentUserPerms();
        // 获取接口所需权限
        RequiresPerm annotation = ((HandlerMethod) handler).getMethodAnnotation(RequiresPerm.class);
        if (annotation != null && !userPerms.contains(annotation.value())) {
            response.setStatus(403);
            return false;
        }
        return true;
    }
    
  • 数据权限校验:通过SQL 拼接 / 数据过滤实现,步骤如下:

    1. 根据当前用户的角色,查询数据权限规则(data_scopedept_ids);
    2. 拼接 SQL 条件,例如:
      • 数据范围为 “本人”:and create_user_id = #{userId}
      • 数据范围为 “本部门”:and dept_id = #{userDeptId}
      • 数据范围为 “指定部门”:and dept_id in (#{deptIds})

五、安全与可扩展考量

  1. 密码安全:用户密码需加盐加密(如 BCrypt),禁止明文存储;
  2. 接口鉴权:所有接口需校验 Token 有效性,防止未授权访问;
  3. 权限操作审计:记录角色分配、权限修改的日志,便于追溯;
  4. 缓存优化:将用户权限、角色信息缓存到 Redis,避免频繁查询数据库;
  5. 多租户隔离:所有表通过tenant_id字段实现数据隔离,权限配置按租户划分;
  6. 临时权限:可在sys_user_permission表中增加expire_time字段,支持用户临时权限分配;
  7. 角色互斥:在sys_role表中增加mutual_exclude_roles字段,避免用户同时拥有互斥角色(如 “财务” 和 “审计”)。

通过以上设计,平台权限系统可实现功能级 + 数据级的精细化控制,同时具备良好的可扩展性和安全性,适配中大型平台的权限管理需求。