【问题标题】:Best way to hide/disable GUI elements based on user's privilege?根据用户权限隐藏/禁用 GUI 元素的最佳方法?
【发布时间】:2011-04-18 09:24:38
【问题描述】:

我正在启动一个 Web 应用程序,客户端用纯 ExtJS 实现,中间层用 Grails 实现。该应用程序具有基于角色的授权,其中用户可以拥有许多细粒度的角色,如 SOME_FORM_READ、SOME_FORM_UPDATE、SOME_DATA_DELETE、SOME_DATA_READ 等。根据用户的角色,需要禁用或隐藏某些 GUI 元素,而其他需要处于只读模式。

我在网上做了一些搜索,但没有找到任何专门解决这个问题的设计模式,所以我想出了自己的设计。我相信很多网络应用程序都会有类似的要求,所以我想在这里发布我的设计并听取人们的意见。我的设计绝不是完美的,但我希望它可以随着大家的投入而改进。虽然我正在使用 ExtJS,但总体设计也应该适用于类似的框架,如 GWT、Flex、Swing 等。

那么,就这样吧:

关于授权,我们需要在客户端层处理四种类型的代码(或信息):

  1. GUI元素操作代码,例如:

    panel.hide() form.setReadOnly(true)

  2. GUI元素权限要求,例如:

    form.requires('READ', 'FORM_READ_ROLE')

    adminPanel.requires('ADMIN_ROLE')

  3. 用户权限信息,基本上是用户拥有的角色列表;

  4. 授权逻辑:根据用户权限确定隐藏/禁用哪些元素;

设计的核心是一个单例,命名为GUIPermissionManager,简称GPM。这是一种集中式设计,因为大部分代码都在 GPM 中,因此 GUI 元素不会被授权代码污染。这就是 GPM 的工作原理:

  • GUI 元素(需要特定权限才能访问)向 GPM 注册其权限信息,如下所示:

    GPM.register(this, 'DEPARTMENT_DELETE_ROLE'); // 删除部门按钮

  • GPM 维护一个 GUI 权限注册列表

  • 在用户登录时,GPM 接收分配给用户的角色列表

  • GPM 遍历 GUI 权限注册列表并根据用户权限确定要隐藏 GUI 的哪个部分,然后相应地调用 element.hide()

问题

  • GUI 元素按树形层次结构组织,例如一个面板包含一个按钮栏和一个表单,所以当面板被隐藏时,不需要进一步检查按钮栏和表单是否需要隐藏。 问题:如何在 GPM 中注册和维护这些分层信息?
  • 目前,我只能想到 GUI 元素的两个用例:隐藏元素或将元素设置为只读(例如表单)。还有其他用例吗?
  • 在ExtJS中,隐藏一个元素,我们调用hide(),但是设置一个表单只读,我们必须想出我们自己的函数,比如说它叫做setReadOnly(),如何让GPM知道哪个调用函数?将函数作为注册的一部分传递?
  • 将表单设置为只读的最佳方法是什么?如果我使用 setReadOnly() 功能扩展表单组件,将会有很多代码重复,我必须为每个需要权限控制的表单执行此操作。是否可以在 GPM 中创建动态表单转换器,以便在表单设置为只读时自动将所有可编辑字段替换为仅显示字段?

【问题讨论】:

  • 您不应该打开一个“问题”并提出 10 个问题。创建多个问题,每个问题都详细说明您要完成的工作,或者只打开一个提出更一般/概念/架构问题的问题.
  • 最后一个问题可能是独立的。但如果脱离讨论上下文,其他 3 个将没有多大意义。

标签: design-patterns gwt user-interface extjs


【解决方案1】:

Q1:分层 UI 元素隐藏 - 优化您的 GPM 以避免隐藏已经通过父级隐藏的元素在我看来不会有太大的性能提升。我的理由:

  1. 您在用户登录时加载一次权限,而不是一直加载。
  2. 根据编码方式,无论如何都需要额外的处理来确定层次结构。
  3. 通过充分的规划,您可以避免注册数十个组件并坚持使用总体容器。

如果您真的想跟踪分层信息,您始终可以使用所有容器组件提供的“包含”方法来检查 DisplayObject 是否包含在其子列表中的任何位置(包括下游)。每次注册组件时都可以调用它以检查它是否已经注册了父级。

然后可以在字典中设置一个标志以忽略隐藏在该组件上。在遍历已注册组件列表以确定应该隐藏的内容时,可以首先检查此标志。字典可以使用与注册组件的 UID 对应的键。此外,当需要忽略其他 GPM 功能时,此标志可用于忽略组件,例如禁用表单(因为无论如何都不会看到表单)。

第二季度。在我的脑海中,您可以禁用/启用组件、实现状态更改或拦截事件以及所有警报。这个问题实在是太宽泛了,因为任何事情都可以做——这完全取决于设计师。

第三季度。你可以:

  1. 在注册组件时提供参数,例如指明它们的类型(用于隐藏的容器、用于设置为只读的表单等)
  2. 在注册时检查每个组件,以确定要对其进行哪些操作。

本质上,您将与 GPM 知道它们的接口并相应地与它们交互的各种组件建立合同。

第四季度。您始终可以将表单设置为禁用(启用 = false)。这可以防止任何用户交互。某些皮肤会更改以指示组件已禁用,因此您可能需要修改它们的皮肤以防止某些这种显示行为。在该行上,您还可以更改他们的皮肤以隐藏某些元素,例如 TextInput 框的边框,使其看起来更像是“视图”而不是禁用的输入。

可以创建一个“转换器”,用 RichText 组件等更改 TextInputs。这将需要大量的工作,并且可能应该构建到扩展的 Form 类而不是 GPM 中。我认为每个组件类型的不同皮肤状态可能是一个更好的解决方案,以避免创建和销毁组件只是为了改变表单的显示方式。

【讨论】:

  • 同意。我还在 ExtJS 论坛上问了同样的问题,那里的人建议我将 GPM 实现为插件并将插件附加到任何需要访问控制的组件,这在我看来是使用 Ext 的正确方法。另一个建议是,每个需要访问控制的 UI 组件都分配一个 ResourceId,并在 GPM 中完成资源 id 和 spring 安全角色之间的映射,这是一个更加集中的设计,并且最大限度地减少了访问控制代码对 UI 代码的污染。跨度>
【解决方案2】:

注意事项!用户权限/授权应该在服务器端控制,而不是在客户端,尤其是基于 js 的 webapps。这是一个很大的安全风险。你应该在你的框架中考虑到这一点。

编辑 - 您的客户端身份验证/隐私管理框架是什么?这将主要指导您的客户端 GUI 管理。

【讨论】:

  • 我在服务器端安装了 Spring Security。在客户端,我只需要隐藏/禁用用户无权访问的 UI 部分。
  • Spring 安全性很好。我同意 J_A_X,这里问了很多问题。另一件事,你似乎在这里过度设计。也许你有非常复杂的角色(需要重新考虑?)。简化的角色管理可以简单地推送到演示者架构中。
  • 权限应该在服务器端控制,但 UI BEHVIOR 不应该。 UI 有一些逻辑来确定如何处理是否取回数据(如果用户无权查看该数据,您将不会从 API 调用中取回数据到后端)。后端无法处理所有愚蠢的事情。后端 API 处理用户是否可以获取数据,仅此而已...基于在验证该用户进行 x 端点调用时存在于后端的底层规则
猜你喜欢
  • 2015-07-27
  • 2022-07-27
  • 2016-05-01
  • 2011-06-24
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多