I m searching for the best way to handle view-level authorization (where you hide markup based on a user s roles).
The typical way to do this is with the Acegi Security authz tag, as follows:
<authz:authorize ifAnyGranted="ROLE_FOO, ROLE_BAR, ROLE_BLAH">
<!-- protected content here -->
</authz:authorize>
The problem with that approach is that it quickly gets messy. For one, you either hard code the user roles as above or you create a constants file that duplicates them all. Second, there s no way with the current scheme to group roles logically. I suppose one solution is to define a separate role for each UI element, but then the declarative method level security on the business methods would need to be updated for each UI element (would that be a good thing?). This would also cause a proliferation of user roles! The use cases for my application actually mandate very few, e.g., Manager, Manager Supervisor, Super User (can do everything), Read Only, etc.
The solution that comes to mind is to treat the authorizable UI elements similar to message resources. That is, define a series of "authorization points" in a properties file similar to a MessageResources file. My initial thoughts are as follows:
com.lingoswap.home.editUserNameButton.ifAnyGranted=ROLE_FOO, ROLE_BAR, ROLE_BLAH
com.lingoswap.home.deleteAccountButton.ifNotGranted=ROLE_NOOB
com.lingoswap.home.deleteAccountButton.ifAnyGranted=ROLE_ADMIN
...
To protect content on the home page, we would then use a different protected tag (one that borrowed heavily from the original authz, possibly a sub class):
<security:protect component="com.lingoswap.home.editUserNameButton">
<!-- edit user name button -->
</security:protect>
<security:protect component="com.lingoswap.deleteAccountButton">
<!-- show the awesome delete account button that s not for nincompoops -->
</security:protect>
The advantages to this approach are the following:
- Easy to test - we can write unit tests that verify the user-role-to-ui-element mappings (of course, it still has to be used on JSPs)
- Error checking at runtime (and test time) - if a user role is misspelled in the .properties file, we can throw an Exception
- Easy to tweak user roles - the requirements team continually refines the user roles; it d be nice to change them all in one central location
- Easy to understand - we can at a glance view the user role permissions for the entire application
- Can be done DRYly (using property Spring placeholders to group related roles, e.g., ${readOnlyGroup} can be used in the properties file instead of the actual role names
The disadvantages seem to be:
- Moderate complexity
- Others??
Thanks for your advice.
Regards, LES2