权限控制是每一个系统都应该有的一个功能,有些只需要简单控制一下就可以了,然而有些却需要进行更加深入和细致的权限控制,尤其是对于一些MIS类系统,基于方法的权限控制就更加重要了。
用反射和自定义注解来实现基于struts2的方法级别的权限控制的主要思想是这样的。
1、先定义一个用于识别在进行action调用的时候标注该方法调用是否需要权限控制,需要什么样的权限的注解类。该注解类一般会包括两个属性,一个是需要的权限,一个是对应的action模块。2、然后就是在需要进行权限控制的action方法上加上该注解类,并标明其应该拥有的权限和对应的action。这样一来在进行action调用的时候可以实现一个自己定义的interceptor来拦截所有的请求,这样在拦截到请求的时候就可以通过ActionInvocation获取到对应的action类的类文件和对应请求的方法名称,然后利用反射来取得action类文件里面对应的请求方法Method,这样就可通过该Method来判断其是否拥有对应的权限控制注解,即看其是否需要进行权限控制,如果需要进行权限控制,就取得该注解并取得其对应的action名称和需要的权限,然后通过session取得当前的用户,并判断当前用户是否拥有对应的某种权限,如果其拥有该权限则继续往下执行,否则,转到自己处理无权限的机制上去。
下面是一段示例代码:
1、定义一个注解,权限配置package com.ljq.action; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; /** * 定义一个注解,权限配置 * * @author jiqinlin * */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Authority { /** 模块 */ String module(); /** 权限值 */ String privilege();}
2、用于拦截请求判断是否拥有权限的拦截器AuthorityInterceptor
package com.ljq.action; import java.lang.reflect.Method;import java.text.SimpleDateFormat;import java.util.Date; import org.apache.log4j.Logger;import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor; /** * 用于拦截请求判断是否拥有权限的拦截器 * * @author jiqinlin * */@SuppressWarnings("serial")public class AuthorityInterceptor extends AbstractInterceptor { private static final Logger logger=Logger.getLogger(AuthorityInterceptor.class); public String intercept(ActionInvocation invocation) throws Exception { String methodName = invocation.getProxy().getMethod(); Class clazz=invocation.getAction().getClass(); //获取类对象 Method currentMethod = clazz.getMethod(methodName); //检查Action类AnnotationTest是否含有@Authority注解 if (currentMethod.isAnnotationPresent(Authority.class)) { // 从session里取得当前的用户 String currentUser = (String) ServletActionContext.getRequest() .getSession().getAttribute("currentUser"); // 取得权限验证的注解 Authority authority = currentMethod.getAnnotation(Authority.class); // 取得当前请求的注解的action String module = authority.module(); // 取得当前请求需要的权限 String privilege = authority.privilege(); /** * 然后可以在此判断当前用户是否拥有对应的权限,如果没有可以跳到指定的无权限提示页面, * 如果拥有则可以 继续往下执行。 * if (拥有对应的权限) { return invocation.invoke(); } * else { return "无权限"; } */ logger.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++"); logger.info("用户["+currentUser+"]在"+new SimpleDateFormat("yyyy-MM-dd hh24:mm:ss").format(new Date()) +"调用了["+clazz.getName()+"]类的["+methodName+"]方法,所在模块["+module+"],拥有权限["+privilege+"]。"); logger.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++"); } return invocation.invoke(); }}
3、需要进行权限控制的Action
package com.ljq.action; import org.apache.struts2.convention.annotation.Action;import org.apache.struts2.convention.annotation.Namespace;import org.apache.struts2.convention.annotation.Result;import org.apache.struts2.convention.annotation.Results; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial")@Namespace(value="/")@Results(value = { @Result(name ="success", location = "/index.jsp"), @Result(name ="add", location = "/index.jsp"),}) @Action(value="action")public class AnnotationAction extends ActionSupport{ //访问路径:http://localhost:8083/struts2_annotation_auth/action!list.htm @Authority(module="annotation", privilege="list") public String list() throws Exception { System.out.println("-------execute---------"); return SUCCESS; } //访问路径:http://localhost:8083/struts2_annotation_auth/action!add.htm @Authority(module = "annotation", privilege = "add") public String add() { System.out.println("-------test---------"); return "add"; } }
4、在struts2的配置文件里面配置自定义的权限控制拦截器
访问,执行结果如下:
[INFO ] [2012-11-29 15:33:26 681]-com.ljq.action.AuthorityInterceptor.44[http-8083-1] - ++++++++++++++++++++++++++++++++++++++++++++++++++++++[INFO ] [2012-11-29 15:33:26 682]-com.ljq.action.AuthorityInterceptor.45[http-8083-1] - 用户[null]在2012-11-29 0324:33:26调用了[com.ljq.action.AnnotationAction]类的[list]方法,所在模块[annotation],拥有权限[list]。[INFO ] [2012-11-29 15:33:26 682]-com.ljq.action.AuthorityInterceptor.47[http-8083-1] - ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------execute---------[INFO ] [2012-11-29 15:33:27 441]-com.opensymphony.xwork2.interceptor.TimerInterceptor.42[http-8083-1] - Executed action [//action!list] took 765 ms.
访问,执行结果如下:
[INFO ] [2012-11-29 15:33:53 604]-com.ljq.action.AuthorityInterceptor.44[http-8083-1] - ++++++++++++++++++++++++++++++++++++++++++++++++++++++[INFO ] [2012-11-29 15:33:53 605]-com.ljq.action.AuthorityInterceptor.45[http-8083-1] - 用户[null]在2012-11-29 0324:33:53调用了[com.ljq.action.AnnotationAction]类的[add]方法,所在模块[annotation],拥有权限[add]。[INFO ] [2012-11-29 15:33:53 605]-com.ljq.action.AuthorityInterceptor.47[http-8083-1] - ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------test---------[INFO ] [2012-11-29 15:33:53 624]-com.opensymphony.xwork2.interceptor.TimerInterceptor.42[http-8083-1] - Executed action [//action!add] took 20 ms.