如何设置权限
xly 的权限模型有两张互补表。它们回答不同问题,并位于不同层;正确阅读这里很重要,因为名字看起来很相似。
两张表
| 表 | 粒度 | 存储内容 | 加载时机 |
|---|---|---|---|
gdsjurisdiction |
每模块 | 每个模块存在的动作 / 按钮目录(BtnAdd、BtnUpd、BtnDel 等) |
每次 getModelBysId(ADMIN 跳过,见切片 1) |
sysjurisdiction |
每角色(也可每用户) | 授权:哪个角色(或用户)可在某模块上执行哪个动作 | 按用户角色在 getModelBysId 中解析;BusinessGdsconfigformsServiceImpl.getJurisdictionData()
|
心智模型:gdsjurisdiction 是框架知道的每模块权限项菜单;sysjurisdiction 是座位表,记录谁能用哪个项。
gdsjurisdiction 包含什么
按模块组织的权限项树:
| 列 | 含义 |
|---|---|
sParentId |
该权限项所属的 gdsmodule.sId
|
sName |
动作 key,例如 BtnAdd、BtnUpd、BtnDel、BtnExport
|
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 根据返回结果启用 / 禁用按钮和列。
如何授予权限
新模块的典型路径:
- 定义模块 + 表单(配方)。
- 为模块暴露的每个按钮 / 动作插入
gdsjurisdiction行(BtnAdd、BtnUpd、BtnExport等),每动作一行,sParentId = 你的模块 sId。 - 决定哪些角色获得哪些动作,插入
sysjurisdiction行:sParentId = module sId、sJurisdictionClassifyId = role sId、sAction = action key。角色级授权保持sUserId为空。 - 如需用户级覆盖,插入带
sUserId的行;每用户覆盖会遮蔽该用户的角色级授权。 - 通过后台保存,让缓存失效传播(运行时按
(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_authority、plat_base_authority_button_type、plat_base_authority_data_type),看起来像按钮类型和数据权限类型 lookup。三张表在实时 DB 中都为空;它们属于不在本 Wiki 范围内的 xlyPlat* B2B 平台层,不属于框架自身权限流。记录框架权限时不要引用它们;上面的权限接口面是自包含的。