7.9 KiB
7.9 KiB
按机构数据隔离改造 —— 设计文档
日期:2026-07-16
背景与目标
当前系统需要按照用户所属机构做数据隔离:例如用户 1 属于机构 A,则用户 1 只能看到机构 A 及机构 A 下属机构的数据。具体要求:
- 用户登录时获取其所属机构 ID(已实现,
authStore.userInfo.organizationId)。 - 所有已有"所属机构"字段的查询页面,该字段默认选中当前登录用户的机构。
- 用户点击"所属机构"选择框改选其他机构时,可选范围只能是"当前用户所在机构及其下属机构",不能显示无权限的机构。
- 角色管理页面目前没有"所属机构"筛选字段,需要新增。
现状调研结论
- 技术栈:Vue 3 + ant-design-vue 4 + Pinia + axios,非 TypeScript,路由/请求封装均已就位,登录态用
access_token(localStorage)+ PiniaauthStore.userInfo(内存,不落盘)。 - 机构选择组件
src/components/OrgTreeSelect.vue已存在并被 15 处表单/筛选框复用,内部调用fetchOrgTreeApi()(GET /api/organization/query-tree)/fetchOrgListAllApi()(GET /api/organization/list-all)获取全量机构数据,当前没有按登录用户做任何范围限制。 - 已有"所属机构"查询筛选字段的页面:
UserList.vue(organizationId)、PersonalList.vue(organizationIdEq)、PersonalCustomerPicker.vue(organizationIdEq,弹窗选择器)。字段命名不统一,以各自后端接口实际入参名为准。 - 角色管理页面(
RoleList.vue)当前只有"角色名称"筛选,没有"所属机构"筛选;后端真实 swagger 确认POST /api/role/page目前只接受roleName/page/pageSize,不接受机构过滤参数(该缺口已在《缺失的后端接口.md》Part 2 第 7 条登记过)。 - 机构模型存在两个不同含义的 id:数字主键
id(被role.organizationId、user.organizationId等外键字段引用,登录/用户信息接口返回的organizationId就是这个数字值)与字符串业务码organizationId(仅用于机构自身管理页 update/delete 定位,以及query-tree的筛选参数)。两者类型不同、不能互相替代,因此前端无法把"当前用户机构数字 id"直接作为现有query-tree的organizationId参数来筛选子树。 - 结论:要做到"下拉框可选范围只能是本机构+下属机构",技术上无法用一次前端 hack 解决,必须由后端基于登录用户的 JWT 身份,在机构树/机构列表接口内部自动限定返回范围。本次改造采用"前端默认值改造 + 记录后端待办"的组合方案,不做前端临时裁剪兼容代码。
方案总览
1. 后端契约变更(登记待办,本次不改后端代码)
在《缺失的后端接口.md》Part 2 追加以下条目(编号从 52 开始):
- 52.
GET /api/organization/query-tree需基于Authorization头中的登录用户身份,自动将返回的机构树限定为"当前用户机构 + 其下属机构"(顶级机构用户仍返回全树),不新增请求参数,现有organizationName/organizationId筛选在此范围内叠加生效。 - 53.
GET /api/organization/list-all同样按登录用户机构自动限定返回的扁平列表范围,规则同上。 - 54.
POST /api/role/page需新增organizationId(数字,机构主键)请求参数,传入时按"该机构及其下属机构"过滤角色列表(呼应 Part 2 第 7 条,补充明确参数名与语义)。 - 55. 安全边界说明:上述改造只解决 UI 展示层"默认值 + 可选范围"的问题;真正的数据安全隔离必须由后端在各业务查询接口内部,基于当前登录用户可见机构范围校验/过滤查询条件与结果,不能仅信任前端传入的
organizationId参数,否则可被直接调用接口绕过,建议在通用鉴权层增加"按机构数据权限"的统一拦截能力。
前端后续调用方式(OrgTreeSelect.vue 内部调用、RoleList.vue 新增筛选字段)保持现有参数不变,一旦后端完成上述改造即可自动获得正确的裁剪效果,前端无需再次改动。在后端完成改造之前,机构下拉框仍会展示全量机构(与现状一致),只是默认选中值会变为当前用户机构。
2. 前端改造范围
新增一个小工具集中获取"当前用户机构 id":
src/utils/orgScope.js:导出getCurrentOrganizationId(),内部读取useAuthStore().userInfo?.organizationId。各页面统一从这里取值,避免重复 import 逻辑分散、便于后续如需调整取值来源时只改一处。
查询/弹窗筛选框默认值改为当前用户机构(可选范围由后端裁剪后自动生效,本次只改默认值):
| 文件 | 字段名 | 改动 |
|---|---|---|
src/views/system/user/UserList.vue |
organizationId |
initial-search 默认值改为 getCurrentOrganizationId() |
src/views/customer/personal/PersonalList.vue |
organizationIdEq |
同上 |
src/components/PersonalCustomerPicker.vue |
organizationIdEq |
同上 |
src/views/system/role/RoleList.vue |
organizationId(新增字段) |
新增筛选表单项(复用 OrgTreeSelect),initial-search 增加该字段并默认选中当前用户机构;ProTable 会原样透传 searchForm 给 fetchRolePageApi,无需额外接线 |
新增表单"所属机构"字段默认值改为当前用户机构(仅影响 create 模式的初始值;edit/view 模式仍回填记录真实值;字段本身仍可编辑,可选范围由后端裁剪):
| 文件 | 表单字段 |
|---|---|
src/views/system/role/RoleList.vue |
新增角色表单 organizationId |
src/views/system/user/UserList.vue |
新增用户表单 organizationId |
src/views/base-config/manager/ManagerList.vue |
新增客户经理表单 organizationId |
src/views/base-config/channel/ChannelList.vue |
新增渠道表单 organizationId |
src/views/customer/personal/PersonalForm.vue |
organizationId |
src/views/customer/enterprise/EnterpriseForm.vue |
organizationId |
src/views/merchant/management/MerchantForm.vue |
organizationId |
src/views/credit/loan-application/PersonalLoanForm.vue |
organizationId |
src/views/credit/loan-application/EnterpriseLoanForm.vue |
organizationId |
src/views/system/org/OrgList.vue |
新增机构表单"上级机构"字段 parentId |
清理:src/components/WalletCustomerPicker.vue 中个人客户查询 initial-search 里未绑定任何 UI 控件的 organizationId: undefined 字段(死代码),顺手删除。
不改动:src/components/OrgTreeSelect.vue 本身的数据加载逻辑(继续调用现有的 fetchOrgTreeApi()/fetchOrgListAllApi(),不传新参数,不做前端二次裁剪,完全信任后端未来返回的已裁剪数据)。
3. 验收标准
- 所有列表 A(见上表)首次进入页面时,"所属机构"筛选框默认值 = 当前登录用户的
organizationId,查询结果与手动选中该机构一致。 - 角色管理页面新增"所属机构"筛选框,默认选中当前用户机构,选择其他机构后请求参数中带上对应
organizationId(受限于后端未支持,实际返回列表暂不会被过滤,这是已知且已登记的后端待办)。 - 所有新增表单 B(见上表)打开"新增"弹窗/页面时,"所属机构"字段默认值 = 当前登录用户的
organizationId,可手动改选(编辑模式不受影响,回显记录原值)。 - 《缺失的后端接口.md》新增 52-55 条待办记录。
WalletCustomerPicker.vue死代码字段已移除,功能不受影响。- 项目可正常
build与dev启动,无报错。
4. 已知限制
- 在后端完成 52/53 条改造之前,机构下拉框仍会展示全量机构列表,只是默认值正确;这是前后端分工下的过渡态,已提前告知。
- 角色列表按机构筛选在后端完成第 54 条改造前不会真正生效。
- 本次改造属于 UI 展示层的默认值与(后端裁剪后自动生效的)可选范围控制,不等同于数据安全隔离;真正的越权防护依赖后端在业务接口内部做机构范围校验(第 55 条)。