當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
基于 Annotation 拦截的 Spring AOP 权限验证方法
生活随笔
收集整理的這篇文章主要介紹了
基于 Annotation 拦截的 Spring AOP 权限验证方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
余 清, 軟件工程師, IBM 簡介: 使用 Annotation 可以非常方便的根據用戶的不同角色,分配訪問 Java 方法的權限。在 Java Web 開發中,使用這種方法,可以提高系統的松耦合度,方便維護。 發布日期: 2013 年 5 月 13 日? 訪問情況 : 4021 次瀏覽? 評論: ?(查看 | 添加評論 - 登錄) 平均分 (11個評分) 為本文評分 在 Web 開發過程中,一個非常理想的開發過程是,開發人員在開發中并不需要關心權限問題,不需要在 Java 方法中寫很多邏輯判斷去判斷用戶是否具有合適的角色和權限,這樣開發會花費非常多的人力成本,因為所有的開發人員都需要了解關于權限的詳細內容,也非常不容易進行后期維護。我們希望有專門的很少數量的開發人員了解權限內容,并且可以隨時方便的修改和配置。于是,我們使用 Annotation,在 Java 方法之前使用 Annotation 可以非常方便的添加,修改和刪除對于權限的管理功能。 本文描述了在開發過程中經常遇到的關于權限驗證問題的一個典型應用案例,這個案例描述如下:系統要求只有登錄用戶才可以下定單。通過這個簡單的例子,我們將看到如何完成整個系統的權限控制。 本文的開發環境如下: Struts2 Spring 3.0 JDK1.6 AspectJ 6.9 本文將分為以下幾個章節,詳細描述提出的權限驗證方法: AOP 的基本概念 權限驗證系統架構詳細講解 AOP 的基本概念 AOP 是 Aspect Oriented Programming 的縮寫,意思是面向方面的編程。我們在系統開發中可以提取出很多共性的東西作為一個 Aspect,可以理解為在系統中,我們需要很多次重復實現的功能。比如計算某個方法運行了多少毫秒,判斷用戶是不是具有訪問權限,用戶是否已登錄,數據的事務處理,日志記錄等等。 一般我們描述一個故事,都會說什么時間什么地點發生了什么事情,那 Join Point 的意思是,發生的地點,Advice 就是發生了什么事,Aspect 就是這個故事的整體,包含了 Join Point 和 Advice。PointCut 又把地點進行了規律性的總結,比如使用正則表達式 (com.example.service.*,即所有在 service 包下面的方法),把所有 Advice 發生的地點進行描述。 讀者現在應該已經大概了解了 AOP 的基本概念,下面我們再來詳細介紹一下: Join Point:表示在程序中明確定義的執行點,典型的 Join Point 包括方法調用,對類成員的訪問以及異常處理程序塊的執行等等,它自身還可以嵌套其它 Join Point。 PointCut:表示一組 Join Point,這些 Join Point 或是通過邏輯關系組合起來,或是通過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。 Advice:Advice 定義了在 PointCut 里面定義的程序點具體要做的操作,它通過 before、after 和 around 來區別是在每個 Join Point 之前、之后還是代替執行的代碼。 回頁首 基于 Annotation 的 Spring AOP 權限驗證方法的實現 Spring AOP 目前只支持基于 method 的 Join Points,而不支持基于 fileds 的 Join Points,也可以使用 AspectJ 去實現基于 fields 的 AOP,這并不會破壞 Spring 的核心 API。 Spring AOP 更傾向于配合 Spring IoC 去解決在企業級系統中更為普遍的問題。 在這個具體的例子中,我們實現了這樣一個場景,在用戶下訂單的時候,先判斷用戶是否已經登錄,如果用戶沒有登錄,系統將轉到登錄頁面,要求用戶登錄。 1. 配置 applicationContext 在 Spring 中支持 AOP 的配置非常的簡單,只需要在 Spring 配置文件 applicationContext.xml 中添加: <aop:aspectj-autoproxy/> 同時在 applicationContext.xml 的 schema 中配置: 清單 1 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"? xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation=" http://www.springframework.org/schema/beans? http://www.springframework.org/schema/beans/spring-beans.xsd? http://www.springframework.org/schema/cache? http://www.springframework.org/schema/cache/spring-cache.xsd? http://www.springframework.org/schema/tx? http://www.springframework.org/schema/tx/spring-tx-3.0.xsd? http://www.springframework.org/schema/aop? http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">? 在配置時,我們需要將引用的 jar 包放置在 WEB-INF/lib 目錄下面: 需要的 jar 包有 配置這些之后 Spring AOP 就可以開始工作了。 2. 定義 Annotation 首先,我們定義一個常量來表示用戶是否登錄: 清單 2 p package com.example.myenum;? public enum ISLOGIN {? YES,? LOGOUT,? NO? }? 這里也可以選擇不使用 enum,UserAccessAnnotation 中的 isLogin() 方法也可以返回整數或 String 類型,返回類型并沒有限制。常量定義之后,我們再定義 Annotation,在 UserAccessAnnotation 中定義 isLogin(),表示用戶是否已經登錄: 清單 3 p package com.example.annotation;? i import java.lang.annotation.ElementType;? i import java.lang.annotation.Retention;? i import java.lang.annotation.RetentionPolicy;? i import java.lang.annotation.Target;? i import com.example.myenum.ISLOGIN;? @Retention(RetentionPolicy.RUNTIME)? @Target(ElementType.METHOD)? public @interface UserAccessAnnotation {? /**? * User has been login or not.? *? */? ISLOGIN isLogin();? }? 定義好之后,這個 Annoatation 將可以被放置在需要驗證用戶是否登錄的方法前面,就像下面這樣: 清單 4 p package com.example.aspect;? p public class OrderAction extends BaseAction{? …… @UserAccessAnnotation(>isLogin=ISLOGIN.YES)? public String Order(){? try{? Boolean result = orderService.order(Quote quote);? if(result) return SUCCESS;? }catch(Exception e) {? logger.debug(e);? this.addActionError(getText("user_no_permission_error"));? }? return INPUT;? }? …… }? 在這里我們使用 UserAccessAnnotation 來表示需要在 Order 方法執行之前判斷用戶是否已經登錄,如果沒有登錄,在 struts2 中,通過下面定義的 Exception 的捕獲機制,將頁面轉到登錄頁面。 3. 在 applicationContext.xml 中定義 Aspect 清單 5 < <bean id="permission" class="com.example.aspect.PermissionAspect" scope="prototype">? <property name="authService" ref="AuthService" />? < </bean>? 我們要在 Spring 中定義 PermissionAspect。在 Struts+Spring 架構中可以把 Aspect 看作是一個 Action,只不過 Aspect 是其他 Action 的前提條件或者結束動作。Aspect 定義中的 Service 屬性和 Action 中的 Service 屬性沒有任何區別。這里我們用 AuthService 類來實現判斷用戶是否已經登錄的邏輯。 4. 定義 PointCut 清單 6 @ @Aspect? p public class SystemArchitecture {? /**? * A Join Point is defined in the action layer where the method needs? * a permission check.? */? @Pointcut("@annotation(com.example.annotation.UserAccessAnnotation)")? public void userAccess() {}? } }? PointCut 即切入點,就是定義方法執行的點,before、after 或者 around。 一般情況下,我們把 PointCut 全部集中定義在 SystemArchitecture 類中,以方便修改和管理。 當實現 Aspect 時可以很方便的使用我們在 SystemArchitecture 中定義的 PointCut。 5. 實現 Aspect 清單 7 package com.example.aspect;? import org.aspectj.lang.annotation.Aspect;? import org.aspectj.lang.annotation.Before;? import com.example.annotation.UserAccessAnnotation;? import com.example.base.action.BaseAction;? import com.example.myenum.USERTYPE;? import com.example.service.AuthService;? @Aspect? public class PermissionAspect extends BaseAction{? …… AuthService authService = null;? @Before(value="com.example.aspect.SystemArchitecture.userAccess()&&"+? "@annotation(userAccessAnnotation)",argNames="userAccessAnnotation")? public void checkPermission(UserAccessAnnotation userAccessAnnotation)? throws Exception{? IsLogin isLogin = userAccessAnnotation.isLogin ();? if(!authService.userLogin(user).equals(isLogin.toString())){? throw new NoPermissionException(getText("user_no_permission_error"));? }? }? …… }? 在 checkPermission 方法前,我們首先定義 PointCut: @Before(value="com.example.aspect.SystemArchitecture.userAccess()&&"+? " "@annotation(userAccessAnnotation)",argNames="userAccessAnnotation"). argNames="userAccessAnnotation" 的意思是把 Annotation 當做參數傳遞進來,并判斷用戶登錄狀態是否與 Annotation 中的定義一致。如果不一致,就要拋出 NoPermissionException,通知系統該用戶沒有權限。 6. 在 Struts action 配置文件中定義 Global Exception 在 Struts.xml 中配置: 清單 8 <global-results>? <result name="loginerror">/WEB-INF/jsp/login.jsp</result>? </global-results>? <global-exception-mappings>? <exception-mapping exception="com.example.exceptions.NoPermissionException"? result="loginerror"/>? </global-exception-mappings>? 經過上面的配置,在 NoPermissionException 拋出之后,Struts2 會 catch 這個 exception,并轉到 login.jsp 頁面。 Annotation 的放置位置時非常靈活的,并不局限于放置在 Struts2 的 Action 之前,若您沒有使用 struts,也可以放置在 Service 類的實現方法之前,讓調用方法捕捉 exception。Aspect 如何處理用戶沒有登錄的情況也可以根據實際需要去實現,同樣不局限于拋出 exception 這種方式。總之,處理方法是非常靈活的,根據讀者的需要可以隨機應變。 回頁首 總結 綜上所述,我們利用在 Struts Action 之前增加 Annotation 的方式非常方便的驗證用戶在系統中的訪問權限。需要驗證登錄與否的方法之前,只要簡單的添加 Annotation,就可以進行登錄判斷。可見,通過這種方式,只需要很少的人力就可以管理整個系統的權限控制。可以很好的控制項目開發的成本,增加系統的靈活性。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的基于 Annotation 拦截的 Spring AOP 权限验证方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vim改装编辑器的安装与使用简介
- 下一篇: JS获取用户控件中的子控件Id