gz-oarms/task_plan.md

12 KiB
Raw Blame History

OARMS 权限体系设计与实现计划

目标

基于 PRD 第三章"角色权限"定义,设计并实现完整的 RBAC + 数据权限体系,覆盖后端认证/鉴权 + 前端路由/按钮控制。

PRD 角色定义

角色 角色代码 操作范围 数据范围
市局广告监管人员 CITY_SUPERVISOR 全模块读写 全市数据
区局广告监管人员 DISTRICT_SUPERVISOR 监控/取证/规则只读 本辖区数据
广告大屏运营商 OPERATOR 大屏维护/录屏查看 本公司大屏数据

当前状态

组件 现状 缺失
Sa-Token 框架 已集成,拦截器已配置 仅 checkLogin无角色/权限校验
LoginController 硬编码 userIdadmin 权限 无数据库校验
StpInterfaceImpl 返回空列表 未对接数据库
UserBaseServiceImpl login() 返回 null 未实现
数据库 无用户/角色表 需建表
前端路由 仅 admin/guest 需增加 3 个角色
前端权限守卫 admin 全通 需角色过滤

实现阶段7 个 Phase

Phase 1数据库设计 — 用户/角色/权限表DDL

在 OARMS schema 下创建系统管理相关表,表前缀 sys_

表设计

1.1 SYS_USER 用户表

列名 类型 说明
ID VARCHAR(32) PK UUID
USERNAME VARCHAR(50) NOT NULL UNIQUE 登录用户名
PASSWORD VARCHAR(100) NOT NULL BCrypt 加密密码
REAL_NAME VARCHAR(50) 真实姓名
PHONE VARCHAR(20) 联系电话
ORG_NAME VARCHAR(100) 所属单位
DISTRICT_CODE VARCHAR(20) 所属区域编码(区局/运营商用)
STATUS TINYINT DEFAULT 1 1=正常 0=停用
+ SuperEntity 审计字段 createBy/createTime/updateBy/updateTime/updateName

1.2 SYS_ROLE 角色表

列名 类型 说明
ID VARCHAR(32) PK UUID
ROLE_CODE VARCHAR(30) NOT NULL UNIQUE 角色编码CITY_SUPERVISOR 等)
ROLE_NAME VARCHAR(50) NOT NULL 角色显示名
DESCRIPTION VARCHAR(200) 描述
STATUS TINYINT DEFAULT 1 1=正常 0=停用
+ SuperEntity 审计字段

1.3 SYS_USER_ROLE 用户角色关联表

列名 类型 说明
ID VARCHAR(32) PK UUID
USER_ID VARCHAR(32) NOT NULL 关联 SYS_USER.ID
ROLE_ID VARCHAR(32) NOT NULL 关联 SYS_ROLE.ID
+ createBy/createTime

1.4 SYS_PERMISSION 权限表(操作权限码)

列名 类型 说明
ID VARCHAR(32) PK UUID
PERM_CODE VARCHAR(50) NOT NULL UNIQUE 权限编码(如 screen:viewevidence:create
PERM_NAME VARCHAR(100) NOT NULL 权限名称
MODULE VARCHAR(30) 所属模块BS/LB/AM/MR/CW
+ SuperEntity 审计字段

1.5 SYS_ROLE_PERMISSION 角色权限关联表

列名 类型 说明
ID VARCHAR(32) PK UUID
ROLE_ID VARCHAR(32) NOT NULL 关联 SYS_ROLE.ID
PERM_ID VARCHAR(32) NOT NULL 关联 SYS_PERMISSION.ID
+ createBy/createTime

1.6 初始数据

3 条角色 + 3 条管理员用户(各角色 1 个)+ 权限码 + 角色权限映射。

权限码清单(按模块):

权限码 说明 市局 区局 运营商
screen:view 查看大屏 Y Y(本辖区) Y(本公司)
screen:create 新增大屏 Y N Y(本公司)
screen:edit 编辑大屏 Y N Y(本公司)
screen:remove 删除大屏 Y N N
screen:export 导出大屏 Y Y(本辖区) N
law:view 查看法律条款 Y Y Y
law:create 新增条款 Y N N
law:edit 编辑条款 Y N N
law:remove 删除条款 Y N N
monitoring-rule:view 查看规则 Y Y N
monitoring-rule:create 新增规则 Y N N
monitoring-rule:edit 编辑规则 Y N N
monitoring-rule:remove 删除规则 Y N N
recording-config:view 查看录屏配置 Y Y(本辖区) Y(本公司)
recording-config:create 新增录屏配置 Y N N
recording-config:edit 编辑录屏配置 Y N N
recording-task:view 查看录屏任务 Y Y(本辖区) Y(本公司)
monitor-record:view 查看监控记录 Y Y(本辖区) N
monitor-record:handle 处理监控 Y Y(本辖区) N
evidence:view 查看取证 Y Y(本辖区) N
evidence:create 固化取证 Y Y(本辖区) N
evidence-relation:view 查看规则关联 Y Y(本辖区) N
evidence-relation:bind 关联规则 Y Y(本辖区) N
monitoring-clue:view 查看线索 Y Y(本辖区) N
monitoring-clue:create 生成线索 Y Y(本辖区) N
clue-transfer:view 查看转办 Y Y(本辖区) N
clue-transfer:create 发起转办 Y Y(本辖区) N

数据权限(不在权限码中,在角色级别控制):

角色 数据范围 实现方式
CITY_SUPERVISOR 全市 无 SQL 过滤
DISTRICT_SUPERVISOR 本辖区 按 district_code 过滤
OPERATOR 本公司 按 org_name 过滤

阶段输出: DDL SQL 文件 + 初始数据 SQL

状态: 完成


Phase 2后端 Entity/Mapper 层

按项目约定创建:

modules/system/
├── entity/
│   ├── SysUserEntity.java
│   ├── SysRoleEntity.java
│   ├── SysUserRoleEntity.java
│   ├── SysPermissionEntity.java
│   ├── SysRolePermissionEntity.java
│   ├── query/
│   │   └── SysUserQuery.java
│   └── vo/
│       ├── SysUserVO.java
│       └── LoginUserVO.java        # 登录后返回给前端的信息
├── mapper/
│   ├── SysUserMapper.java
│   ├── SysRoleMapper.java
│   ├── SysUserRoleMapper.java
│   ├── SysPermissionMapper.java
│   └── SysRolePermissionMapper.java
└── service/
    ├── ISysUserService.java
    ├── ISysRoleService.java
    └── impl/
        ├── SysUserServiceImpl.java
        └── SysRoleServiceImpl.java

关键方法

  • SysUserMapper.findByUsername(username) — 登录查询
  • SysRoleMapper.selectByUserId(userId) — 查用户角色
  • SysPermissionMapper.selectByUserId(userId) — 查用户权限码
  • SysPermissionMapper.selectByRoleCode(roleCode) — 查角色权限

LoginUserVO 返回给前端的信息:

{
  "userId": "...",
  "username": "...",
  "realName": "...",
  "roles": ["CITY_SUPERVISOR"],
  "roleNames": ["市局广告监管人员"],
  "permissions": ["screen:view", "screen:create", ...],
  "districtCode": null,
  "orgName": "广州市市场监督管理局"
}

状态: 完成


Phase 3认证流程实现LoginController + StpInterfaceImpl

3.1 LoginController 改造

POST /user/auth/login
  → SysUserService.findByUsername(username)
  → BCrypt.checkPassword(password, user.password)
  → StpUtil.login(user.id)
  → session.set(USER_KEY, LoginUserVO)
  → response.setHeader("satoken", token)
  → return RestResult.ok(LoginUserVO)

3.2 StpInterfaceImpl 实现

getPermissionList(loginId) → SysPermissionMapper.selectByUserId(loginId)
getRoleList(loginId) → SysRoleMapper.selectRoleCodesByUserId(loginId)

3.3 /user/auth/login/info 改造

返回 LoginUserVO含 roles + permissions + districtCode + orgName

3.4 UserBaseServiceImpl 完善

  • login() 对接 SysUserService
  • getCurrentUser() 从 session 取 LoginUserVO

状态: 完成


Phase 4鉴权拦截器 + 数据权限

4.1 SpringMvcConfig 权限路由

按模块配置权限检查:

SaRouter.match("/api/screen/**", r -> StpUtil.checkLogin());
SaRouter.match("/api/monitoring-rule/**", r -> {
    StpUtil.checkLogin();
    // 具体 CRUD 方法用注解控制
});
// ... 其余模块类似

4.2 Controller 方法级权限注解

在需要权限控制的 Controller 方法上加:

@SaCheckPermission("screen:create")
@PostMapping("save")
public RestResult<?> save(...) { ... }

@SaCheckPermission("screen:remove")
@PostMapping("remove")
public RestResult<?> remove(...) { ... }

4.3 数据权限过滤

在 Service 层的查询方法中,根据当前用户的角色过滤数据:

  • CITY_SUPERVISOR: 不过滤
  • DISTRICT_SUPERVISOR: 在 Query 中追加 district_code = currentUser.districtCode
  • OPERATOR: 在 Query 中追加 org_name = currentUser.orgName

实现方式:在 Service 中获取当前用户,动态拼装查询条件。

注意:数据权限需要修改现有 10 个模块的 Service 查询方法,影响范围较大。建议先实现 Phase 1-3 的认证和操作权限Phase 4 数据权限单独迭代。

实际实施

  • 创建 DataScopeHelper 工具类(modules/system/util/),提供角色判断静态方法
  • 修改 7 个 Service 的 queryList 方法,添加数据权限过滤:
    • ScreenServiceImpl: queryList + exportData + getScreenOptions
    • RecordingConfigServiceImpl: queryList + getConfigurableScreens
    • RecordingTaskServiceImpl: queryList
    • MonitorRecordServiceImpl: queryList
    • EvidenceRecordServiceImpl: queryList
    • MonitoringClueServiceImpl: queryList
    • ClueTransferServiceImpl: queryList + queryPendingClues
  • 过滤规则:
    • CITY_SUPERVISOR: 不过滤(全市数据)
    • DISTRICT_SUPERVISOR: 按 district = currentUser.districtCode 过滤
    • OPERATOR: Screen 按 operatorUnit = orgName,其他模块通过 screenId 关联 Screen 过滤
  • ClueTransferServiceImpl 特殊处理OR 条件(转办目标辖区 + 线索来源辖区)
  • 跳过模块LawClauseServiceImpl无区域字段、MonitoringRuleServiceImpl复杂 scope JSON、EvidenceRuleRelationServiceImpl关联表

状态: 完成


Phase 5前端角色路由映射

5.1 定义角色常量

// src/utils/constants.js 或 src/router/roles.js
export const ROLES = {
  CITY_SUPERVISOR: 'CITY_SUPERVISOR',
  DISTRICT_SUPERVISOR: 'DISTRICT_SUPERVISOR',
  OPERATOR: 'OPERATOR'
}

5.2 更新 routes.js 的 meta.roles

按 PRD 权限矩阵为每个业务路由分配角色:

// BS-大屏基础库 - 三个角色都能访问
meta: { roles: [ROLES.CITY_SUPERVISOR, ROLES.DISTRICT_SUPERVISOR, ROLES.OPERATOR] }

// MR-监测规则 - 市局+区局
meta: { roles: [ROLES.CITY_SUPERVISOR, ROLES.DISTRICT_SUPERVISOR] }

// CW-内容预警 - 市局+区局
meta: { roles: [ROLES.CITY_SUPERVISOR, ROLES.DISTRICT_SUPERVISOR] }

5.3 更新 permission.js

  • 去掉 admin 硬编码全通逻辑
  • 使用后端返回的 permissions 数组做按钮级控制

5.4 按钮级权限指令

添加 v-permission 指令,控制按钮显示:

<el-button v-permission="'screen:create'">新增</el-button>
<el-button v-permission="'screen:remove'">删除</el-button>

状态: 完成


Phase 6用户管理接口可选

提供用户 CRUD 接口供后台管理使用:

  • POST /api/sys-user/query — 用户列表(分页)
  • POST /api/sys-user/save — 新增用户
  • POST /api/sys-user/update — 编辑用户
  • POST /api/sys-user/remove — 删除用户
  • POST /api/sys-user/reset-password — 重置密码
  • GET /api/sys-user/role-options — 角色选项列表

前端对应的管理页面可后续迭代。

状态: pending


Phase 7编译验证 + 端到端测试

  1. DDL 执行到 DM8 数据库
  2. 后端编译通过(mvn compile -Dcheckstyle.skip=true
  3. 启动后端,验证登录流程
  4. 验证权限校验(无权限返回 403
  5. 前端 npm run lint 通过
  6. 前端登录后路由正确过滤

状态: 完成BUILD SUCCESS


实施建议

优先级排序

优先级 Phase 说明
P0 必须 Phase 1-3 DDL + Entity/Mapper + 认证流程,使登录对接真实数据库
P1 重要 Phase 5 前端角色路由,使不同角色看到不同菜单
P2 增强 Phase 4 操作权限注解 + 数据权限过滤
P3 可选 Phase 6 用户管理 CRUD
P0 验证 Phase 7 编译 + 测试

建议实施路径

第一轮(核心认证): Phase 1 → 2 → 3 → 7 第二轮(前端权限): Phase 5 → 7 第三轮(精细控制): Phase 4 → 6


修复决策

(实施过程中记录)