通過SpringMVC+Annotation實現方法、按鈕級別的細粒度權限控制

隨着企業信息化的不斷深入,各種各樣的信息系統成爲提高企業運營及管理效率的必備工具,越來越多的企業核心機密如銷售機會、客戶資料、設計方案等通過信息系統存儲、備案、流轉,這些核心資料一旦外泄,勢必對企業造成極大損失。科技時代,信息是企業生存的命脈,信息的安全也必然成爲企業極度重視的問題。如今,隨着各種信息安全措施的實施,信息泄密已經從外部泄漏向內部人員泄漏轉移。外部的黑客、病毒要想獲取有價值的信息,必須穿透多道防火牆,逃避多重殺毒工具的追殺,再對信息進行篩選才能如願以償;而內部人員知道什麼信息是有價值的,如果不對信息進行必要的安全防護,企業內部一些有有心人員會十分容易地獲取自己所需要的信息資料。

最近的一份調查顯示,幾乎有一半的各行各業專業人士承認當他們跳槽時會帶走資料,包括文件、銷售協議和合同清單等各種資料,並將它們告訴下一個老闆。調查還發現,八成的職員可以輕鬆地下載“有競爭力”的資料和信息,然後帶到下一份工作中。

信息安全任重而道遠。要保證信息系統的安全,需要考慮到很多方面如防火牆、加密傳輸、防SQL注入等,但很多的安全方案都是從如何把守大門着手的,如身份認證、數字證書,不管是傳統的用戶名加口令方式還是基於生物特徵識別的指紋、視網膜掃描技術,乃至各類電子政務領域常用的USBkey都是在進入系統大門時大做文章,一旦身份識別完成進入大門後,卻聽之任之,很少再有處理方案。本文重點不在如何進行身份認證,而在身份認證完成後也即進入系統大門後,如何保證用戶只在自己有權限的範圍內進行操作,而不是可以進行任意功能的操作即系統內部細粒度權限控制解決方案。


常用的權限系統設計模式是以角色爲核心的,即角色是具有相同權限的一類人員的集合:

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;
	}

}

至此,基於按鈕、方法驗證的細粒度權限體系完成!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章