The other day I had to mess around with struts-menu. struts-menu is a neat little Struts plugin that draws drop-down Javascript menus on web pages. It's been quite useful thankyou very much, if a little sparsely documented.
I needed to make certain menu options disappear based on who was logged in. There's some example code for menu permissions provided with the struts-menu download. Matt Raible has a demo of it online. I couldn't find anything that vaguely resembled task-focused documentation, though.
Eventually, I worked out how it's done. Mostly by reading the source-code. Hence this write-up. I hope Google will make sure the next person with the same problem finds their way here, so they don't have to repeat the mild discomfort I had to go through to gather this information.
Goal
To limit access to particular menu items based on the application's security configuration.
Background: PermissionsAdapter
Checking the Javadoc, you'll find the PermissionsAdapter Interface. This interface has one method: "isAllowed(MenuComponent)" that is called for each menu and menu item when the menu is being drawn. If it returns true, the item is drawn, if it returns false, the item is not drawn. (Some menu implementations may draw, but disable disallowed menu items)
struts-menu comes with a single concrete implementation of the PermissionsAdapter, called RolesPermissionsAdapter. This adapter maps the user's security roles as defined in the application/appserver configuration against a list of permitted roles defined for each menu/menu item in menu-config.xml
Step 0: Define your roles
This is part of your general J2EE/JAAS/etc security configuration. Each user or group will be allocated roles. Those roles are mapped to role definitions in the application's configuration. It's a very good idea to sit down at a whiteboard with your use cases and map out what the various roles are and what they're allowed to do before implementing anything.
Step 1: Define a PermissionsAdapter for the menu
The JSP tag you use to display the menu, <menu:useMenuDisplayer/> has an optional property: "permissions". If this property is present, it's used as the key with which to look up an instance of PermissionsAdapter in the application/request/session/page scope. It will then apply that adapter to the menu.
There is, however, a "magic" value for this property, "rolesAdapter". This magic value tells the menu displayer that instead of looking for an adapter in scope, it should instead create a new instance of RolesPermissionsAdapter and use that instead.
So, step 1 is to go through all your invocations of <menu:useMenuDisplayer/> and add permissions="rolesAdapter"
to the tag.
Step 2: Map roles to menu items in menu-config.xml
The <Menu/> and <Item> tags in your menu configuration file (which is variable, but I shall refer to as menu-config.xml) have an optional "roles" attribute. This attribute, when used in conjunction with the RolesPermissionsAdapter, is a space-separated list of all the roles that will be permitted to use a particular menu or menu-item.
RolesPermissionsAdapter works by splitting the list, and calling request.isUserInRole()
for each one. If any of them come back true, the menu or menu item is displayed.
So, for the following menu item definitions:
<Menu name="PrefsMenu" title="Preferences" roles="User"> <Item name="UserPrefs" title="User Preferences" page="prefs.do"/> <Item name="ModPrefs" title="Moderator Preferences" page="modPrefs.do" roles="Moderator System"/> <Item name="AdminPrefs" title="Site Preferences" page="sitePrefs.do" roles="System"/> </Menu>
The menu is visible to anyone in the User role, who then get access to User Preferences automatically. Anyone in the System or Moderator roles can access the moderator preferences, but the site preferences are limited only to System-level users.
Of course, this doesn't prevent people accessing the page in ways other than using the menu, but it's polite not to present people with options that you know they can't take advantage of.
Anyway, I hope this is of some use to someone other than me.