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?