permissions.md 5.06 KB

如何设置权限

xly 的权限模型有两张互补表。它们回答不同问题,并位于不同层;正确阅读这里很重要,因为名字看起来很相似。

两张表

粒度 存储内容 加载时机
gdsjurisdiction 模块 每个模块存在的动作 / 按钮目录BtnAddBtnUpdBtnDel 等) 每次 getModelBysId(ADMIN 跳过,见切片 1
sysjurisdiction 角色(也可每用户) 授权:哪个角色(或用户)可在某模块上执行哪个动作 按用户角色在 getModelBysId 中解析;BusinessGdsconfigformsServiceImpl.getJurisdictionData()

心智模型:gdsjurisdiction 是框架知道的每模块权限项菜单sysjurisdiction座位表,记录谁能用哪个项。

gdsjurisdiction 包含什么

按模块组织的权限项树:

含义
sParentId 该权限项所属的 gdsmodule.sId
sName 动作 key,例如 BtnAddBtnUpdBtnDelBtnExport
sChinese / sEnglish / sBig5 显示标签(如 新增
iOrder 权限 UI 中的排序
sBrandsId / sSubsidiaryId 租户作用域

当前实时 DB 中有 4,335 行 gdsjurisdiction,覆盖 892 个不同模块和 186 个不同动作名。gdsjurisdiction 包含角色列或用户列,它只是目录。

sysjurisdiction 包含什么

真实授权:

含义
sParentId 授权所属模块 sId
sParent2Id 父模块(组 / 分类),供权限 UI 渲染树使用
sJurisdictionClassifyId 角色 / 权限分类 id(到 sisjurisdictionclassify 的 FK 语义)
sUserId 用户 id,用于每用户覆盖;为空表示“角色级授权”
sAction 被授予的动作,例如 BtnBsOperation.BtnDesignFunction
sKey 复合路径 key,编码拥有该动作的模块层级

当前实时 DB 中有 28,045 行 sysjurisdiction全部都是角色级(每个 sUserId 都为空):22 个角色 × 各角色可使用的模块和动作。

BusinessGdsconfigformsServiceImpl.getJurisdictionData(第 212 行)在用户级和角色级授权之间选择:

Boolean hasCheckUser = checkUserJurisdiction(map);
if (hasCheckUser) {
    return this.getGroupJurisdictionUserNew(map);  // 每用户覆盖
} else {
    return this.getGroupJurisdictionNew(map);      // 仅角色 fallback
}

如果调用用户在 sysjurisdiction 中有任何带其 sUserId 的行,则用户路径胜出;否则使用角色路径。当前 dev DB 中用户路径不可达。

请求中如何加载权限

BusinessBaseServiceImpl.getModelBysId 中相关伪代码:

List<Map<String, Object>> jList = new ArrayList<>();
if (!UserType.ADMIN.getTypeName().equals(map.get("sUserType"))) {
    jList = businessGdsconfigformsService.getJurisdictionData(qMap);
}
returnMap.put("gdsjurisdiction", jList);

ADMIN 完全绕过权限并得到空授权列表,SPA 将其解释为“显示所有按钮”。非管理员用户得到其角色 + 模块 + 租户可解析出的动作过滤列表。SPA 根据返回结果启用 / 禁用按钮和列。

如何授予权限

新模块的典型路径:

  1. 定义模块 + 表单(配方)。
  2. 为模块暴露的每个按钮 / 动作插入 gdsjurisdiction 行(BtnAddBtnUpdBtnExport 等),每动作一行,sParentId = 你的模块 sId
  3. 决定哪些角色获得哪些动作,插入 sysjurisdiction 行:sParentId = module sIdsJurisdictionClassifyId = role sIdsAction = action key。角色级授权保持 sUserId 为空。
  4. 如需用户级覆盖,插入带 sUserId 的行;每用户覆盖会遮蔽该用户的角色级授权。
  5. 通过后台保存,让缓存失效传播(运行时按 (sUserId, sModelsId, sBrandsId, sSubsidiaryId) 缓存 getJurisdictionData,见第 209 行的 @Cacheable)。

ADMIN 特例

硬编码的 ADMIN 绕过是真实逃生口。按约定每个部署至少有一个 ADMIN 账号。从安全审计角度,ADMIN 访问应在外部严格控制和审计;框架本身没有应用内限制。

跨租户边界不是权限

需要明确:gdsjurisdiction + sysjurisdiction 强制的是租户内权限。跨租户边界(一家公司不能读取另一家公司数据)由多租户作用域强制,即自动注入 sBrandsId / sSubsidiaryId,不是由 jurisdiction 规则强制。

关于 plat_base_authority_*

schema 中有三张 plat_base_authority 下的表(plat_base_authorityplat_base_authority_button_typeplat_base_authority_data_type),看起来像按钮类型和数据权限类型 lookup。三张表在实时 DB 中都为空;它们属于不在本 Wiki 范围内的 xlyPlat* B2B 平台层,不属于框架自身权限流。记录框架权限时不要引用它们;上面的 jurisdiction surface 是自包含的。