Appfuse的許可權控制依賴於Struts的Menu機制,common下的menu.jsp是對選單順序的定義,詳細的選單項和選單連結及許可權再menu-config.xml中控制,如下:
<Menu name="Logout" title="user.logout" page="/logout" roles="ROLE_ADMIN,ROLE_USER,ROLE_PRODUCT" />
roles中的值即是role表中的name,給那個角色分配選單的許可權,則把角色的name加入到選單定義的roles中即可。
但使用過程中會發現,這樣定義好之後選單出來是亂的,源自appfuse中的一個Bug,修改檔案navbarMenu.vm即可,如下:
1 #macro( displayNavbarMenu $menu $count) 2 #if ($displayer.isAllowed($menu)) 3 #set ($count = $count + 1) 4 ## set menu title 5 #set ($title = $displayer.getMessage($menu.title)) 6 #if (!$menu.url) #set ($url="javascript:void(0)") #else #set ($url=$menu.url) #end 7 8 ## create a single menu item 9 #if ($menu.components.size() == 0) 10 <li class="#if ($menu.name == $currentMenu)active#end"> 11 <a href="$url" title="$title" #if($menu.target)target="$menu.target" #end#if($menu.width)style="width: ${menu.width}px"#end>${title}</a> 12 #else ## create multiple menu items in a menu 13 #if ($menu.components.size() > 0) 14 #set ($hasViewableChildren = false) 15 #set ($renderedChildren = 0) 16 #foreach ($menuIt in $menu.components) 17 #if ($displayer.isAllowed($menuIt)) 18 #set($hasViewableChildren = true) 19 #set($renderedChildren = $renderedChildren + 1) 20 #end 21 #end 22 #end 23 24 <li#if ($hasViewableChildren) class="dropdown#if ($menu.name == $currentMenu) active#end"#end> 25 <a href="#" title="$title" 26 #if($menu.target)target="$menu.target" #end 27 #if($menu.width)style="width: ${menu.width}px"#end 28 class="dropdown-toggle" data-toggle="dropdown">${title}</a> 29 #end 30 31 #if ($menu.components.size() > 0) 32 #if ($hasViewableChildren) 33 <ul class="dropdown-menu"> 34 #end 35 36 #set ($count = 0) 37 #foreach ($menuIt in $menu.components) 38 #displayNavbarMenu($menuIt, $count) 39 #end 40 41 #if ($hasViewableChildren && ($count == $renderedChildren)) 42 </ul></li> 43 #else 44 </ul> 45 #if ($count > $renderedChildren) 46 </li> 47 #end 48 #end 49 #else 50 </li> 51 #if ($menu.parent && $count == $menu.parent.components.size()) 52 ##</ul> 53 #end 54 #end 55 #end 56 #end 57 58 #displayNavbarMenu($menu, 0)
使用Menu控制許可權只能控制到選單的可見性,如果想深入到資料控制需要自己再處理。下面是通過切入OnSubmit方法做的操作控制:
1. 首先定義切面,切入OnSubmit方法
1 /** 2 * 做許可權驗證,如果使用者無許可權,則拒絕請求 3 */ 4 @Override 5 public Object invoke(MethodInvocation invocation) throws Throwable { 6 try { 7 Boolean allow = false; 8 // 當前執行的操作 9 String action = ""; 10 // 獲取當前操作的使用者的角色 11 User user = userManager.get(getCurrentUserID()); 12 Set<Role> roleList = user.getRoles(); 13 // 當前執行的操作,從Request中獲取 14 // 基於OnSubmit的簽名獲取RequestString onSubmit(Greatplace greatplace, 15 // BindingResult errors, HttpServletRequest request, 16 // HttpServletResponse response) 17 if (invocation.getArguments().length == 4 18 && invocation.getArguments()[2].getClass() == HttpServletRequest.class) { 19 HttpServletRequest request = (HttpServletRequest) invocation 20 .getArguments()[2]; 21 if (request.getParameter("save") != null) { 22 action = RolePermissionManager.PERMISSION_SAVE; 23 } else if (request.getParameter("delete") != null) { 24 action = RolePermissionManager.PERMISSION_DELETE; 25 } else if (request.getParameter("approve") != null 26 || request.getParameter("unapprove") != null) { 27 action = RolePermissionManager.PERMISSION_APPROVE; 28 } 29 for (Role r : roleList) { 30 allow = RolePermissionManager.hasPermission(r.getName(), 31 action); 32 if (allow) 33 break; 34 } 35 if (!allow) { 36 request.getSession().setAttribute("successMessages", 37 "對不起,您無權執行該操作!"); 38 return request.getPathInfo().replace("/", ""); 39 } 40 } 41 Object result = invocation.proceed(); 42 return result; 43 44 } catch (IllegalArgumentException ex) { 45 log.error(ex); 46 throw ex; 47 } 48 }
2. 定義自己的許可權驗證方法,下面是個簡單的示例
public class RolePermissionManager { /** * 許可權項:儲存 */ public static final String PERMISSION_SAVE = "save"; /** * 許可權項:審批 */ public static final String PERMISSION_APPROVE = "approve"; /** * 許可權項:刪除 */ public static final String PERMISSION_DELETE = "delete"; /** * 角色:管理員 */ public static final String ROLE_ADMIN = "ROLE_ADMIN"; /** * 角色:普通使用者 */ public static final String ROLE_USER = "ROLE_USER"; /** * 基於角色的許可權矩陣 */ private static Map<String,List<String>> permissionList; /** * 初始化角色的許可權項 */ public RolePermissionManager(){ } /** * 判斷當前角色是否有指定的許可權項 * @param roleName 角色名稱 * @param permissionName 許可權項名稱 * @return */ public static Boolean hasPermission(String roleName,String permissionName){ return getPermissionList().get(roleName).contains(permissionName); } /** * 定義角色和許可權項的規則 * @return */ public static Map<String,List<String>> getPermissionList(){ if(permissionList == null){ permissionList = new HashMap<String,List<String>>(); //定義管理員的許可權 List<String> adminPermissionList = new ArrayList<String>(); adminPermissionList.add(PERMISSION_SAVE); adminPermissionList.add(PERMISSION_APPROVE); adminPermissionList.add(PERMISSION_DELETE); permissionList.put(ROLE_ADMIN, adminPermissionList); //定義普通使用者的許可權 List<String> userPermissionList = new ArrayList<String>(); permissionList.put(ROLE_USER, userPermissionList); } return permissionList; } }
這樣基本的許可權控制目的就能達到。
關於使用者看到的資料許可權我通過url中的引數,結合search來控制,但這樣只要修改url中的引數就可越過資料許可權,有待優化。