`

使用Spring的AOP拦截DispatchAction

阅读更多
红色部分是个人心得

最近做的一个项目中对权限要求比较高,对系统每个模块的不同操作(CRUD)分别设置权限,当然用户还有角色,多对多的关系,默认用户继承所拥有的角色(按优先级从高到低)的权限,也可以对用户单独授权,整体采用RBAC模型,ACL的主体可以为角色也可以为用户,做完授权后,下一步的问题时:如何及时认证呢?三个参数(用户ID, 资源ID, 操作permission) ,因为UI层使用Struts,用户登陆后可以在request中获取session,进而获取用户ID,资源ID可以从request的servletPath中URL查出,剩下的就是操作了,这是最关键的一点。

    系统的命名规范是(C)--->add... / (R)--->find/   (U)--->modify...   / (D)--->del.. 针对每个模块编写一个Action继承BaseAction,BaseAction继承DispatchAction,在你要拦截的DispatchAction中重写execute()方法,否则拦截不到,重写的方法我会在下面贴出来.完成用户登陆验证后交由DispatchAction根据parameter执行任务分发,说到这里就会想到用Spring的AOP来对所有的Action进行拦截,然后定义pointcut为这些Action的add..或 del...开头的方法,在根据pointcut定义不同的adviser,对应的adviser中规定好对应的permission(第三个参数),在结合从JoinPoint中获取的request,得到前两个参数完成及时认证。想法不错,然而做起来的时候,却不是那么回事,因为所有的Action都是DispatchAction,所有的方法(非execute())均为反射调用,所以根本拦截不到其他的跟业务逻辑相关的add..或 del...开头的方法,所以,现在的问题是:如何用AOP对DispatchAction中的不同方法进行拦截?

    分析Struts的执行过程和DispatchAction的原理就知道,拦截DispatchAction的execute()方法,在adviser中做DispatchAction中的一些类似的处理,比如获取parameter和methodName,得到了methodName,不就可以设置permission了吗!

核心的代码贴出来,Aspect如下:


AuthImpl.java
package com.bluesun.oa.manager.impl;

/* import ... */

public class AuthImpl implements Auth {

private ACLManager aclManager;

public void authPermission(JoinPoint joinPoint) {
   Object[] args = joinPoint.getArgs();
   ActionMapping mapping = (ActionMapping) args[0];
   ActionForm form = (ActionForm) args[1];
   HttpServletRequest request = (HttpServletRequest) args[2];
   HttpServletResponse response = (HttpServletResponse) args[3];

   String parameter = mapping.getParameter();
   if (parameter == null) { // 非DispatchAction, 无需检查权限
    return;
   }

   String methodName = request.getParameter(parameter);
   int permission = -1;

  if (methodName == null) { // unspecified()方法
    permission = Permission.READ;
   } else if (methodName.startsWith("add")) {
    permission = Permission.CREATE;
   } else if (methodName.startsWith("modify")) {
    permission = Permission.UPDATE;
   } else if (methodName.startsWith("del")) {
    permission = Permission.DELETE;
   } else {
    return; // 其他情况不做检查
   }

   User user = (User) request.getSession().getAttribute("login");
   if (user == null) {
    return;   //用户没登陆,不检查权限,交由BaseAction处理
   }

   String path = request.getServletPath();
   String moduleUrl = null;
   if (path != null && path.length() > 1) {
    moduleUrl = path.substring(1);
   }

   if (!aclManager.hasPermission(user.getId(), moduleUrl, permission)) {
    throw new SystemException("对不起,您无权执行此操作,请联系管理员! [color=red][b]这里一定要抛异常,因为无法跳转,跳转回出错.抛出异常后,用用户自定义异常处理方式处理,在处理方法中可以让其跳到指定页面.[/b][/color]username:" + user.getUsername());
   }
}

public void setAclManager(ACLManager aclManager) {
   this.aclManager = aclManager;
}

}



AOP的配置:

applicationContext.xml
<bean id="auth" class="com.bluesun.oa.manager.impl.AuthImpl">
   <property name="aclManager" ref="aclManager"/>
</bean>

/ *       more code       */

<aop:config proxy-target-class="true">
   <aop:aspect id="authAspect" ref="auth">
    <aop:pointcut id="authP" expression="execution(* com.bluesun.oa.web.actions.*.execute(..))"/>
    <aop:before pointcut-ref="authP" method="authPermission"/>
   </aop:aspect>
</aop:config>




重写execute
	
public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception{
                //这里可以写一些你的处理代码,不写也可以
		ActionForward af = super.execute(mapping, form, request,response);
		SaveErrors(request);
		return af;
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics