使用Struts2的拦截器和自定义注解方式实现权限控制
您目前处于:技术核心竞争力  2013-12-31

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

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 框架中继承的标签。


转载请并标注: “本文转载自 linkedkeeper.com ”  ©著作权归作者所有