根据用户权限隐藏/禁用 GUI 元素的最佳方法?
我正在启动一个 Web 应用程序,其客户端在纯 ExtJS 中实现,中间层在 Grails 中实现。该应用程序具有基于角色的授权,其中用户可以拥有许多细粒度的角色,例如 SOME_FORM_READ、SOME_FORM_UPDATE、SOME_DATA_DELETE、SOME_DATA_READ 等。根据用户的角色,某些 GUI 元素需要禁用或隐藏,而其他元素则需要禁用或隐藏。处于只读模式。
我在网上做了一些搜索,但没有找到任何专门解决这个问题的设计模式,所以我想出了自己的设计。我确信很多 Web 应用程序都会有类似的要求,所以我想在这里发布我的设计并听取人们的意见。我的设计绝不是完美的,但我希望它能在大家的意见下得到改进。虽然我正在使用 ExtJS,但总体设计也应该适用于类似的框架,如 GWT、Flex、Swing 等。
所以,这里是:
我们需要在客户端处理四种类型的代码(或信息)关于授权:
GUI元素操作代码,例如:
面板.隐藏() form.setReadOnly(true)
GUI元素权限要求,例如:
form.requires('READ', 'FORM_READ_ROLE')
adminPanel.requires('ADMIN_ROLE')
用户权限信息,这基本上是用户拥有的角色列表;
授权逻辑:根据用户权限决定隐藏/禁用哪些元素;
设计的核心是一个单例,名为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 中创建动态表单转换器,以便如果表单设置为只读,它会自动将所有可编辑字段替换为仅显示字段?
I am starting a web application with client side implemented in pure ExtJS and middle tier in Grails. The application has role-based authorization, where a user can have many fine grained roles like SOME_FORM_READ, SOME_FORM_UPDATE, SOME_DATA_DELETE, SOME_DATA_READ, etc. Based on the roles of the user, certain GUI elements need to be disabled or hidden, while others need to be in a read-only mode.
I did some search on the web, but didn't find any design pattern that specifically addresses this issue, so I came up with my own design. I am sure that a lot of the web applications out there will have a similar requirement, so I'd like to post my design here and hear people's opinion on it. By no means is my design a perfect one, but I hope it can be improved with everyone's input. Although I am working with ExtJS, the general design should also apply to similar frameworks like GWT, Flex, Swing, etc.
So, here it goes:
There are four types of code (or information) we need to deal with in the client tier regarding authorization:
GUI element manipulation code, for example:
panel.hide()
form.setReadOnly(true)GUI element permission requirement, for example:
form.requires('READ', 'FORM_READ_ROLE')
adminPanel.requires('ADMIN_ROLE')
User privilege information, which is basically a list of roles that the user has;
Authorization logic: determines which elements to hide/disable based on user privilege;
The core of the design is a singleton, named GUIPermissionManager, or GPM for short. This is a centralized design in that most of the code is in GPM, so that GUI elements are not polluted by the authorization code. This is how GPM works:
GUI elements (that need certain permission to access) register their permission information with GPM, like this:
GPM.register(this, 'DEPARTMENT_DELETE_ROLE'); // button for deleting a department
GPM maintains a list of GUI permission registration
On user login, GPM receives the list of roles the use is assigned
GPM walks through the GUI permission registration list and based on user privilege, determines which part of the GUI to hide, and in turn, calls element.hide() accordingly
Questions:
- GUI elements are organized in a tree hierarchy, e.g. a panel contains a button bar and a form, so when the panel is hidden, there is no need to check further if the button bar and the form need to be hidden. Problem: how to register and maintain this hierarchical information in GPM?
- Currently, I can only think of two use cases for GUI element: hide an element or set an element as read-only (such as a form). Is there any other use cases?
- In ExtJS, to hide an element, we call hide(), but to set a form read-only, we have to come up with our own function, let's say it's called setReadOnly(), how to let GPM know which function to call? Passing the function as part of the registration?
- What is the best way to set a form read-only? If I extend the form component with the setReadOnly() functionality, there will be a lot of code duplication and I have to do this for every form that need permission control. Is it possible to create a dynamic form transformer in GPM so that if a form is set to read-only, it automatically replaces all editable fields with display-only fields?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Q1:分层 UI 元素隐藏 - 在我看来,优化 GPM 以避免隐藏已经通过父级隐藏的元素不会有太大的性能提升。我的原因:
如果您确实想跟踪层次结构信息,您始终可以使用所有容器组件提供的“contains”方法来检查 DisplayObject 是否包含在其子列表中的任何位置(包括下游链)。每次注册组件时都可以调用它来检查它是否已经有注册的父组件。
然后可以在字典中设置一个标志来忽略该组件上的隐藏。在迭代注册组件列表以确定应隐藏哪些内容时,可以首先检查此标志。字典可以使用与注册组件的 UID 相对应的键。此外,当需要忽略其他 GPM 功能时,例如表单禁用(因为表单永远不会被看到),此标志可用于忽略该组件。
Q2。在我的脑海中,您可以禁用/启用组件、实现状态更改或拦截事件和所有警报。这确实是一个太宽泛的问题,因为任何事情都可以做——这完全取决于设计师。
Q3。您可以:
您本质上是与各种组件建立契约,其中 GPM 知道它们的接口并相应地与它们交互。
Q4。您始终可以将表单设置为禁用(enabled = false)。这会阻止任何用户交互。某些外观将发生更改以指示组件已禁用,因此您可能需要修改其外观以防止某些此类显示行为。在该行中,您还可以更改它们的外观以隐藏某些元素,例如 TextInput 框的边框,以便使其看起来更像是“视图”而不是禁用的输入。
可以创建一个“转换器”来使用 RichText 组件等更改 TextInputs。这将需要大量的工作,并且可能应该构建到扩展的 Form 类而不是 GPM 中。我认为每个组件类型的不同皮肤状态可能是更好的解决方案,以避免仅仅为了改变表单的显示方式而创建和销毁组件。
Q1: Hierarchical UI element hiding - Optimizing your GPM to avoid hiding elements that are already hidden via a parent is not going to have much of a performance boost in my opinion. My reasons:
If you really want to keep track of hierarchical information you can always use the 'contains' method that all container components provide for checking if a DisplayObject is contained anywhere in its child list (including down the chain). This could be called up each time a component is registered to check if it already has a registered parent.
A flag could then be set in a dictionary to ignore hiding on that component. This flag could get checked first while iterating over the list of registered components to determine what should be hidden. The dictionary could use keys that correspond to the registered component's UID. Furthermore this flag could be used to ignore the component when it comes time to ignore other GPM functions, like form disabling (as the form would never be seen anyways).
Q2. Off the top of my head you could disable/enable components, implement state changes, or intercept events, and all alerts. This is really too broad of a question as anything could be done - really up to the designer.
Q3. You could:
You would essentially be establishing a contract with various components where the GPM is aware of their interfaces and interacts with them accordingly.
Q4. You can always set a form to be disabled (enabled = false). This prevents any user interaction. Some skins will change to indicate that the components are disabled so you may want to modify their skins to prevent some of this display behavior. On that line, you could also change their skins to hide certain elements such as the TextInput box's border so as to make it look more like a 'view' than a disabled input.
It would be possible to create a 'transformer' that changes TextInputs with RichText components and such. This would take a decent amount of work and should probably be built into an extended Form class instead of the GPM. I think different skins states for each component type may be a better solution, so as to avoid creation and destruction of components just to change how the form appears.
请注意!用户权限/授权应该在服务器端控制,而不是在客户端,特别是对于基于 js 的 Web 应用程序。这是一个很大的安全风险。您应该在您的框架中考虑这一点。
编辑-您的客户端身份验证/隐私管理框架是什么?这将主要指导您的客户端 GUI 管理。
A note of caution! User priviledges/authorization should be controlled on the server side and not on the client side especially for js based webapps. Its a big security risk. You should consider that in your framework.
edit - what is your framework for client side auth/priv management? That will mostly direct your client side GUI management.