使用Struts2的攔截器和自定義注解方式實現權限控制
1. 自定義注解的編寫:@interface
說明:使用Spring的AOP也可以實現權限的控制,但是經過Spring的AOP方法處理后再交給Struts2時,注意Struts2中上下文參數丟失問題。
Struts2的攔截器使用了動態代理,從動態代理類中獲取調用方法名并通過invocation.getAction().getClass().getMethod(methodName)獲取被調用的方法。然后根據session中保存的用戶權限和從方法注解中獲取的權限進行判斷,看用戶是否具有調用該方法的權限進行處理。
下面是使用Struts2的Interceptor攔截器實現權限控制的例子:
這里我們使用注解為每個Action的方法聲明權限。
首先創建自定義注解Permission,用于設置權限:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permission {
/** 權限名稱 */
String privilege();
}
其中的Permission的module和privilege為模塊和模塊對應的權限,每個用戶登錄時都把權限信息保存到session中,方便在攔截器中對權限的判斷。
2. Struts2 Interceptor攔截器的編寫和配置
1、 編寫一個攔截器實現Interceptor接口或者繼承AbstractInterceptor
接下來最重要的就是編寫攔截器對權限進行判斷,并作出正確的處理:
public class PrivilegeInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 742285864455102141L;
/**
* 1、通過動態代理類和反射機制獲取調用的方法
* 2、獲取方法的Permission注解
* 3、獲取Permission中包含的權限信息(構造SystemPrivilege權限類)
* 4、和用戶的權限信息進行對比(PrivilegeGroup中的SystemPrivilege)判斷用戶的權限
*/
@Override
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
if(WebUtil.getRequestURI(request).startsWith("/cms/control/")){
ActionProxy actionProxy = invocation.getProxy();
String methodName = actionProxy.getMethod();
if (StringUtils.isBlank(methodName)) {
methodName = "execute";//默認方法
}
Class aClass = actionProxy.getAction().getClass();
Method method = aClass.getMethod(methodName);
if(method != null && method.isAnnotationPresent(Permission.class)){
System.out.println("Call the Action Method:" + method.toString());
//獲取當期執行的Action上的注解
Permission permission = method.getAnnotation(Permission.class);
if (permission != null) {
System.out.println("當前需要的權限為:" + permission.module());
//獲取當期執行的Action方法需要的權限
SystemPrivilege methodPrivilege = new SystemPrivilege(permission.privilege());
//WebUtil.getEmployee(request) 方法是從session中獲取保存的employee信息,包括權限集合
Employee employee = WebUtil.getEmployee(request);
//循環判斷用戶是否具有該權限,如果有則繼續執行,否則返回提示視圖
for(PrivilegeGroup group : employee.getGroups()){
if(group.getPrivileges().contains(methodPrivilege)){
return invocation.invoke();
}
}
System.out.println("權限不足");
return "privilegemessage";
}
}
System.out.println("未設置權限");
return invocation.invoke();
}
System.out.println("所有權限");
return invocation.invoke();
}
}</code></pre>
2、 在struts.xml文件中注冊自定義攔截器
3、 在需要使用的Action中引用自定義攔截器。
在想要設置權限的方法加入自定義的Permission注解用于標識該方法的權限:
@Permission(privilege="confirmOrder")
public String confirmOrder(){
…
}
3. Struts2攔截器原理
AOP面向切面編程和動態代理
下面開始講一下主菜ActionProxy了,在這之前最好先去了解一下動態Proxy的基本知識。
ActionProxy是Action的一個代理類,也就是說Action的調用是通過ActionProxy實現的,其實就是調用了ActionProxy.execute()方法,而該方法又調用了ActionInvocation.invoke()方法。歸根到底,最后調用的是DefaultActionInvocation.invokeAction()方法。
DefaultActionInvocation()->init()->createAction()。
最后通過調用
ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction() 這里的步驟是先由ActionProxyFactory創建ActionInvocation和ActionProxy。

一個請求在Struts2框架中的處理分為以下幾個步驟:
1.客戶端發出一個指向servlet容器的請求(tomcat);
2.這個請求會經過圖中的幾個過濾器,最后會到達FilterDispatcher過濾器。
3.過濾器FilterDispatcher是struts2框架的心臟,在處理用戶請求時,它和請求一起相互配合訪問struts2的底層框架結構。在web容器啟動時,struts2框架會自動加載配置文件里相關參數,并轉換成相應的類。
如:ConfigurationManager、ActionMapper和ObjectFactory。ConfigurationManager 存有配置文件的一些基本信息,ActionMapper存有action的配置信息。在請求過程中所有的對象(Action,Results,Interceptors,等)都是通過ObjectFactory來創建的。過濾器會通過詢問ActionMapper類來查找請求中需要用到的Action。
4.如果找到需要調用的Action,過濾器會把請求的處理交給ActionProxy。ActionProxy為Action的代理對象。ActionProxy通過ConfigurationManager詢問框架的配置文件,找到需要調用的Action類。
5.ActionProxy創建一個ActionInvocation的實例。ActionInvocation在ActionProxy層之下,它表示了Action的執行狀態,或者說它控制的Action的執行步驟。它持有Action實例和所有的Interceptor。
6.ActionInvocation實例使用命名模式來調用,1. ActionInvocation初始化時,根據配置,加載Action相關的所有Interceptor。2. 通過ActionInvocation.invoke方法調用Action實現時,執行Interceptor。在調用Action的過程前后,涉及到相關攔截器(intercepetor)的調用。
7. 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標簽。
來自:http://www.linkedkeeper.com/detail/blog.action?bid=60