UI 约束
安装
请按照 扩展组件 章节的介绍通过 Jmix 市场自动安装。
手动安装步骤:
-
配置 premium 仓库的访问:
-
在
build.gradle添加 premium 仓库:repositories { // ... maven { url = 'https://global.repo.jmix.io/repository/premium' credentials { username = rootProject['premiumRepoUser'] password = rootProject['premiumRepoPass'] } } } -
将 premium 仓库的凭证记录在
~/.gradle/gradle.properties文件中:premiumRepoUser=123456123456 premiumRepoPass=abcdefabcdef仓库的凭证可以通过许可秘钥获取:秘钥中短横前的部分为用户名,短横后的部分为密码。例如,如果你的秘钥是
123456123456-abcdefabcdef,则用户名是:123456123456,密码是abcdefabcdef。
-
-
在
build.gradle中添加依赖:implementation 'io.jmix.uiconstraints:jmix-uiconstraints-starter'
用法
UI 约束扩展组件提供了 UI 组件策略,可以在 资源角色 中配置。既支持开发时通过带注解的 Java 接口配置,也支持运行时通过角色管理视图进行配置。
Java 接口中用到的 @UiComponentPolicy 注解在 策略注解 部分介绍。
运行时的角色编辑器可以通过主菜单 Security → Resource roles 访问。当应用程序中包含 UI 约束扩展组件时,策略的下拉列表中会包含 UI component policy 选项:
UI 组件策略编辑器支持指定目标视图,并从下拉列表中选择已有的组件然后配置策略操作和效果:
与实体和实体属性策略不同,UI 组件策略是“拒绝”策略,即,使用这个策略只能使 UI 组件或操作的可见性或可访问性低于策略使用之前的状态。例如,如果某个实体属性在实体属性策略中配置了可见,则 UI 组件策略可以使该属性对应的 UI 组件不可见(设置 VISIBLE 操作为 DENY 效果)。请参阅 effect。
UI 组件策略在视图打开过程的最后应用,即在 ReadyEvent 发送之后。此时,视图的所有初始化工作都已完成,且已经应用了其他策略。
检查 UI 组件策略
使用 UiComponentPolicyContext 和 AccessManager bean 检查当前用户的策略是否允许显示或编辑某个组件或操作。传入视图 ID 和组件路径,格式与 componentIds 属性相同,例如 emailField、addressFragment.streetField 或 userGrid.edit。
以下示例检查策略是否允许在 Customer.detail 视图中显示和编辑 emailField:
@Autowired
private AccessManager accessManager;
private boolean isEmailFieldEditable() {
UiComponentPolicyContext context =
new UiComponentPolicyContext("Customer.detail", "emailField");
accessManager.applyRegisteredConstraints(context);
return context.isVisiblePermitted() && context.isEnabledPermitted();
}
调用 applyRegisteredConstraints() 后,使用 isVisiblePermitted() 和 isEnabledPermitted() 读取权限。这两种权限初始均为 true;除非另一个约束拒绝访问,否则未被任何策略提及的组件都是允许的。
该上下文检查的是策略权限,而不是组件当前状态或其实体属性权限。即使组件因其他原因被隐藏、禁用或设为只读,该策略判定允许也不会使其可见或可编辑。
内置的 UiComponentPolicyConstraint 会评估当前用户的有效策略。UiComponentPolicyApplier 在应用策略时使用相同的上下文。应用程序可以注册 AccessConstraint<UiComponentPolicyContext>,通过 setVisibleDenied() 或 setEnabledDenied() 进一步限制访问。拒绝的结果会由 AccessLogger 记录。
对动态内容应用策略
对于视图打开后创建的组件,请注入 UiComponentPolicyApplier,然后在将组件添加到视图后调用 applyUiComponentPolicies(view, content),将视图的策略应用于该组件及其子组件。组件和操作的 ID 必须与其策略路径匹配。
@Autowired
private UiComponentPolicyApplier uiComponentPolicyApplier;
private void addRuntimeContent(Component content) {
getContent().add(content);
uiComponentPolicyApplier.applyUiComponentPolicies(this, content);
}
单参数方法 applyUiComponentPolicies(content) 会通过组件树查找组件的所属视图。如果找不到视图,则不会应用任何策略。
对于 tabSheet 标签页中的内容,请使用双参数方法 applyUiComponentPolicies(view, content)。JmixTabSheet 仅在组件树中保留选中标签页的内容,并在客户端响应之前才 attach,因此单参数方法无法可靠地找到所属视图。
标签页选择
默认情况下,扩展组件在标签页被选中时对其内容应用策略。也包括 <tab lazy="true"> 中的组件和操作,其内容仅在首次选中时创建。懒加载标签页无需应用程序代码即可应用策略。
每个内容组件只处理一次。再次选择同一标签页不会对应用程序已做的组件更改重新应用策略,传递给 applyUiComponentPolicies() 的内容也会标记为已处理。
如果某个策略隐藏了选中的标签页,则用户在使用视图时可能会选中另一个标签页。
如需禁用标签页选择时自动应用策略,请将 jmix.uiconstraints.apply-policies-on-tab-selection 设置为 false。此时,视图打开后创建的内容(包括懒加载标签页内容)不会自动应用策略。
UiComponentPolicy 注解
编程时,可以使用 @UiComponentPolicy 注解在 资源角色 接口中定义 UI 约束。
示例:
package com.company.demo.security;
import com.company.demo.view.customer.CustomerDetailView;
import com.company.demo.view.customer.CustomerListView;
import io.jmix.security.role.annotation.ResourceRole;
import io.jmix.uiconstraints.annotation.UiComponentPolicy;
import io.jmix.uiconstraints.annotation.UiComponentPolicyAction;
import io.jmix.uiconstraints.annotation.UiComponentPolicyEffect;
@ResourceRole(name = "EmployeeRole", code = EmployeeRole.CODE, scope = "UI")
public interface EmployeeRole {
String CODE = "employee-role";
@UiComponentPolicy(
viewClass = CustomerListView.class,
componentIds = {"customersDataGrid.importCustomersAction"},
action = UiComponentPolicyAction.ENABLED,
effect = UiComponentPolicyEffect.DENY
)
@UiComponentPolicy(
viewClass = CustomerDetailView.class,
componentIds = {"commentsPane"},
action = UiComponentPolicyAction.VISIBLE,
effect = UiComponentPolicyEffect.DENY
)
void customers();
}
@UiComponentPolicy 注解的属性如下:
componentIds
每个 @UiComponentPolicy 注解可以为视图中的一个或多个 UI 组件定义策略。组件的 ID 必须在 componentIds 属性中列出。支持为下列 UI 组件类型配置策略:
-
给定视图中的可视化组件(
textField、button、vbox、div等)。示例:firstNameField、importButton。 -
给定视图中的操作。示例:
save。 -
UI 组件的操作。示例:
userGrid.edit。 -
fragment 中的组件或操作。示例:
addressFragment.cityField。
效果
effect 属性可以配置两个值之一:ALLOW 或 DENY。
默认情况下,如果未应用 UI 组件策略,则视图中的所有 UI 组件都具有原本的可见性和可访问性状态。如果存在相应的实体属性策略,则与数据绑定组件是可见和可访问的。
如果在 UI 组件策略中指定了 DENY 效果,则会隐藏或禁用 UI 组件或操作。这是 UI 组件策略的最常见用法。
如果需要覆盖由其他角色对同一组件应用的另一个 UI 组件策略,则可以使用 ALLOW 效果。例如,如果已为用户分配了 A 角色,并且此角色禁止访问某个 UI 组件,则可以配置一个 B 角色,对同一组件配置 ALLOW 效果即可恢复对该组件的访问。
ALLOW 效果无法显示/启用由于初始状态或对应实体或实体属性权限缺失而隐藏/禁用的组件。
|
Application Properties
jmix.uiconstraints.apply-policies-on-tab-selection
Jmix 3.1+
控制是否在选择标签页时应用 UI 组件策略,也包括懒加载标签页中的内容。参考 标签页选择。
默认值:true。
设置为 false 禁用此处理。当视图打开时,策略仍然会应用,也可以使用 UiComponentPolicyApplier 以编程方式应用策略。