常用的權限系統設計模式是以角色為核心的,即角色是具有相同權限的一類人員的集合:
1. 一個角色可以有包含多個操作人員,一個操作人員也可以屬於多個角色
2. 一個角色可以具有多個功能的操作權限,一個功能也可以被多個角色所擁有。
在登錄時通過查詢登錄用戶所屬角色,即可得到個用戶的所有功能集合,如下圖:
多數業務系統的頁 面功能菜單設計是以三級為標准的,即一級功能菜單、二級功能菜單、三級功能菜單,通常情況下一二級功能菜單只是用於功能分類,是不具有功能訪問地址的,三 級菜單才是功能的真正入口,常規權限系統就是通過控制每個人員對應的功能菜單的顯示與隱藏來實現權限控制。要實現細粒度權限控制,可在設計功能表時再加入 第四層:頁面元素,隸屬於第三層功能菜單,這些頁面元素用來標識功能頁面中的每一個功能按鈕,如增加、修改、刪除、查詢都可算是頁面元素,在為角色分配權 限時,第四層也同樣納入統一權限管理,如果有此頁面元素的權限,則頁面上就顯示該按鈕,如果沒有此頁面元素的功能權限,則該按鈕就不會顯示出來。
對於沒有權限訪問的功能或頁面除了進行前台的隱藏之外,還需要在后台訪問時進行權限的驗證,否則操作人員繞開頁面直接通過輸入URL訪問功能就會造成權限漏洞,通過SpringMVC+Annotation的方式可以輕松實現,代碼如下:
第一步:創建SpringMVC攔截器,攔截所有需要進行權限驗證的功能請求
<!-- 開啟注解 --> <mvc:annotation-driven/> <!-- 靜態資源訪問 --> <mvc:resources location="/static/" mapping="/static/**"/> <!-- 攔截器 --> <mvc:interceptors> <!-- 多個攔截器,順序執行 --> <mvc:interceptor> <!-- 如果不配置或/**,將攔截所有的Controller --> <mvc:mapping path="/**" /> <!-- 在Freemarker界面展示之前做一些通用處理 --> <bean class="xx.xxxx.core.web.FreeMarkerViewInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
第二步:創建作用於Method級別的Annotation類,用於傳入功能ID
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Permission { /** * 功能ID,該功能ID,對應數據庫中的功能ID * @return * @version V1.0.0 * @date Jan 13, 2014 4:59:35 PM */ String value(); }
第三步:通過靜態常量建立數據庫中的功能ID與執行方法的一對一關系
public class FuncConstants { /** * 系統管理-角色管理-增加角色 */ public final static String Xtgl_Jsgl_AddJs = "4399d98bb0d84114acb5693081e83bc9"; /** * 系統管理 - 部門管理- 部門列表 */ public final static String Xtgl_Bmgl_BmList = "dbc4bf80f8b6418788b79de204d37932"; }
第四步:在SpringMVC攔截器中驗證權限
/** * FreeMarker視圖攔截器,頁面展示之前做一些通用處理 * @version V1.0.0 * @date Dec 12, 2013 4:20:04 PM */ public class FreeMarkerViewInterceptor extends HandlerInterceptorAdapter { public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView view) throws Exception { String contextPath = request.getContextPath(); if (view != null) { request.setAttribute("base", contextPath); } } public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //處理Permission Annotation,實現方法級權限控制 HandlerMethod method = (HandlerMethod)handler; Permission permission = method.getMethodAnnotation(Permission.class); //如果為空在表示該方法不需要進行權限驗證 if (permission == null) { return true; } //驗證是否具有權限 if (!WebUtil.hasPower(request, permission.value())) { response.sendRedirect(request.getContextPath()+"/business/nopermission.html"); return false; } return true; //注意此處必須返回true,否則請求將停止 //return true; } }
至此,基於按鈕、方法驗證的細粒度權限體系完成!