跳转到内容

数据权限

概念理解

环境变量

MS & 业务模块配置ACL和UC的环境变量:

Terminal window
ACL_MOCK=false;
USER_MOCK=false;
ACL_CLIENT_HOST=;
ACL_ADMIN_HOST=;
UC_PROTOCOL=;
UC_FRONT_URL=;
LOGIN_SHARE_COOKIE_NAME=;

注解手动开关鉴权

业务模块可通过配置环境变量来控制默认默认鉴权开关:DEFAULT_ENABLED_AUTHENTICATION

数据权限应当只过滤页面请求的模型数据,而非后端业务逻辑对模型的所有查询操作。因此,默认且推荐DEFAULT_ENABLED_AUTHENTICATION=false同业务的模块请保持默认开关一致

0.17.58.RELEASE,新增了两个注解用于手动控制 func/flow 的鉴权开关,使用时标记在实现类上

  • @DataPermissionAuth:强制执行鉴权
  • @SkipDataPermissionAuthentication :跳过鉴权
package io.terminus.trantorframework.sdk.permission;
/**
* 在 method 上注解,该 method 内对 DataStore 的调用会执行数据权限的鉴权
* 在 class 上注解,该 class 内所有对 DataStore 的调用都会执行数据权限的鉴权
* 仅在方法主线程中生效,在自开线程与远程调用中无效
* <p>
* 自开线程在调用 DataStore 前可通过手动调用 {@link io.terminus.trantor.api.TContext#enableDataPermission} 强制鉴权
* 该方法作用域为方法调用所在线程
*/
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermissionAuth {
}
package io.terminus.trantorframework.sdk.permission;
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipDataPermissionAuthentication {
}

规则

  • 同业务的模块请保持默认开关一致默认且推荐关闭自动鉴权
  • 鉴权开关优先级:生效注解 > 默认鉴权
  • Trantor 系统自带的API,例如 load-data 等总是走鉴权的
  • 调用链路上,遇到当前生效注解,会向下传播。

生效注解

DEFAULT_ENABLED_AUTHENTICATION=false时,调用链路会忽略@SkipDataPermissionAuthentication,代码请仅使用@DataPermissionAuth,反之同理。

DEFAULT_ENABLED_AUTHENTICATION鉴权生效注解
false@DataPermissionAuth
true@SkipDataPermissionAuthentication

直接调用鉴权:

实现类标注鉴权
Skip@SkipDataPermissionAuthentication
Enforce@DataPermissionAuth
Default/DEFAULT_ENABLED_AUTHENTICATION

DEFAULT_ENABLED_AUTHENTICATION=false,观察下表调用链路与鉴权逻辑,不难看出SkipDefault表现一致,反之同理。(7-8)跨模块调用时,当调用链路遇到@DataPermissionAuth也会向下传播开启强制鉴权:

序号调用链路鉴权
1Skip —> Enforce—>DefaultSkip❌ —> Enforce✅ —> Default✅
2Default —> Enforce —>DefaultDefault❌ —> Enforce✅ —> Default✅
3Enforce —> SkipEnforce✅—> Skip✅
4Enforce —> DefaultEnforce✅ —> Default✅
5Skip —> DefaultSkip❌—> Default❌
6Default —> SkipDefault❌ —> Skip❌
7A.Enforce —> B.Skip—> C.Whatever…A.Enforce✅—> B.Skip✅—> C.Whatever…✅
8A.Skip —> B.Enforce—> C.Whatever…A.Skip❌ —> B.Enforce✅—> C.Whatever…✅

鉴权流程

  1. 在研发态配置数据权限;
  2. 发布数据权限所属模块到运行环境;
  3. 为角色分配数据权限;
  4. 资源点鉴权;

数据权限配置

数据权限分行数据权限和列数据权限,行数据权限需要先在交付控制台的研发态配置,设置需要对哪些模型的字段设置规则。列数据权限在统一工作台配置,设置字段的可见性、以及读写权限。

配置业务模型数据权限

配置数据权限时,需要设置资源标识、资源名称,以及影响的模型和规则字段。其中

  • 影响模型,即数据权限需要对哪个模型表设置规则。

  • 规则字段,即需要根据哪个字段设置查询条件过滤表数据。

roleAuth

配置非持久化模型数据权限

视图页面绑定的模型可能是非持久化模型,如果需要对页面设置数据权限,需要额外配置非持久化模型射的实体模型和实体字段。这里映射的实体模型,即查询非持久化模型数据时,实际查询的物理表所对应的实体模型。

roleAuth

业务变量

在配置规则字段时,可以通过变量管理设置变量,这个变量和上下文相关,在配置字段的查询条件时,可以根据业务上下文获取具体的值。

  • 勾选规则字段,可进行变量管理操作
  • 输入变量名称及获取方法
img

获取方法需要填入业务上下文的表达式。这里的变量实际是从业务上下文中引一个资源声明在鉴权时需要根据上下文获取业务变量的值来过滤指定的业务数据

数据权限资源发布

因为功能权限属于模块资源,执行发布计划的时候,类型选择“模块”,并选择需要发布的模块,以及目标环境。完成资源的发布后,可以在运行环境模块菜单下查看配置的数据权限。如下图所示:

roleAuth

角色配置数据权限

行数据权限授权

业务规则

  • 授权需要指定数据权限点,然后定义这个数据权限点的数据规则。数据权限树来源于交付控制台的配置,数据规则的维度来源于交付控制台上,对于规则字段的配置。每个数据权限上面的tips,来自于交付控制台的权限说明。
  • 不同的字段类型,可配置的规则和交互不同

1619054531209-1ebbf3a9-2f1f-4424-bbcd-873d55902acc

在统一工作台角色管理页面,选择某个角色,或者创建新的角色,在操作列中点击“行数据权限”按钮,打开数据权限授权页面,选择数据权限点,并设置具体的字段过滤条件。

字段如果在交付控制台配置变量管理,在设置变量的条件时,可以选择业务变量。

img
  • 以如上字段类型为例,用户在赋权限规则时引入对变量的选择
  • 选择业务变量,选择在交付控制台配置的变量信息,完成授权配置

列数据权限授权

业务规则

  • 原则上列级别的权限,系统里的所有字段都可以被配置,但绝大部分列其实都在业务中定义了读写规则,多数对列的控制需求都是禁用列级别的读和写,因此,在trantor的机制里,对于列权限的控制,使用的反向授权。
  • 用户从所有模型中选择需要控制字段,加入到被控制的字段列表后,在读写规则中,选择禁止读取/禁止写入,完成对列级别的反向控制。
  • 移除权限后,则恢复为权限系统未控制的状态,根据业务系统的规则走。

roleAuth

FAQ

鉴权失败如何排查?

  1. 检查环境变量是否配置正确。

  2. 若使用了业务上下文,在业务服务的最近日志中查找关键字Invalid permission,一般可以看到权限点失效的原因。

  3. 开启业务服务debug日志,在最近日志中查找关键字Permission add sql,即可看到鉴权拼接后的查询语句。

    logging:
    level:
    io.terminus.trantorframework.permission: debug
  4. 查看DS日志。

为何推荐关闭自动鉴权?

数据权限应当只过滤页面请求的模型数据,而非后端业务逻辑对模型的所有查询操作。

因此,关闭数据权限,并在界面的数据来源Viewfunc/flow(视图、模型导出)的实现类上标记@DataPermissionAuth是才最优解。

image-20210816170347987

自动鉴权改用手动注解,需要哪些操作?

Step 1

将所有模块DEFAULT_ENABLED_AUTHENTICATION=true删掉或置false

Step 2

找出视图/导出模版所用的所有func/flow

主ms数据库,执行下述sql查询语句 (需要系统表权限)

SELECT DISTINCT
SUBSTRING_INDEX(
SUBSTRING_INDEX(
meta.result,
' ',
mht.help_topic_id + 1
),
' ',- 1
) AS result
FROM
((
SELECT DISTINCT
*
FROM
(
SELECT
ExtractValue ( `code`, '//*/attribute::dataFlow|//*/attribute::dataFunc|//*/attribute::dataFunction' ) AS result
FROM
meta_store_management__versioned_view
) AS meta
WHERE
(
meta.result IS NOT NULL
AND meta.result != ''
AND meta.result NOT REGEXP 'BuiltInFunc|taurus|import_export_center'
)) UNION
(
SELECT DISTINCT
functionKey AS result
FROM
meta_store_management__versioned_model_data_template
WHERE
templateType = 'Export'
AND functionKey IS NOT NULL
)) AS meta
JOIN mysql.help_topic AS mht ON mht.help_topic_id < (
length( meta.result )- length(
REPLACE ( meta.result, ' ', '' ))+ 1
);
WHERE
(
result IS NOT NULL
AND result != '')

普通账号权限可以使用下述sql,因为视图可以有多个数据容器,下述sql查出来的数据可能会有一行多个funckey的情况,因此去重效果也不好:

(SELECT DISTINCT*FROM (
SELECT ExtractValue (`code`,'//*/attribute::dataFlow|//*/attribute::dataFunc|//*/attribute::dataFunction') AS functionKey FROM meta_store_management__versioned_view) AS meta WHERE (meta.functionKey IS NOT NULL AND meta.functionKey !='' AND meta.functionKey NOT LIKE '%BuiltInFunc')) UNION (
SELECT DISTINCT functionKey FROM meta_store_management__versioned_model_data_template WHERE templateType='Export' AND functionKey IS NOT NULL);

Step 3

先检查下Viewfunc/flow是否有被其他func/flow调用的情况:

  • 否,则在实现类上标记注解@DataPermissionAuth即可。
  • 是,可以再抽象一层ViewFuncWithAuth,实现类标记@DataPermissionAuth,去调用原来的Viewfunc/flow。再将视图的dataFunc/dataFlow或导出模版的functionKey改为新建ViewFuncWithAuth的key。