zoukankan      html  css  js  c++  java
  • 基于 Annotation 的 Spring AOP 权限验证方法的实现

    1. 配置 applicationContext

    在 Spring 中支持 AOP 的配置非常的简单,只需要在 Spring 配置文件 applicationContext.xml 中添加:

    <aop:aspectj-autoproxy/>

    同时在 applicationContext.xml 的 schema 中配置:

    清单 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <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 包有

    需要的 jar 包有

    配置这些之后 Spring AOP 就可以开始工作了。

    2. 定义 Annotation

    首先,我们定义一个常量来表示用户是否登录:

    清单 2
    1
    2
    3
    4
    5
    6
    package com.example.myenum;        
        public enum ISLOGIN {
            YES,
            LOGOUT,
            NO
        }

    这里也可以选择不使用 enum,UserAccessAnnotation 中的 isLogin() 方法也可以返回整数或 String 类型,返回类型并没有限制。常量定义之后,我们再定义 Annotation,在 UserAccessAnnotation 中定义 isLogin(),表示用户是否已经登录:

    清单 3
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.example.annotation;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    import com.example.myenum.ISLOGIN;
     
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.METHOD)
        public @interface UserAccessAnnotation {
             /**
             * User has been login or not.
             *
             */
            ISLOGIN isLogin();
        }

    定义好之后,这个 Annoatation 将可以被放置在需要验证用户是否登录的方法前面,就像下面这样:

    清单 4
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.example.aspect;
    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
    1
    2
    3
    <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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Aspect
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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:

    1
    2
    @Before(value="com.example.aspect.SystemArchitecture.userAccess()&&"+
    "@annotation(userAccessAnnotation)",argNames="userAccessAnnotation").

    argNames="userAccessAnnotation" 的意思是把 Annotation 当做参数传递进来,并判断用户登录状态是否与 Annotation 中的定义一致。如果不一致,就要抛出 NoPermissionException,通知系统该用户没有权限。

  • 相关阅读:
    010-spring事务管理
    009-事务管理
    008-ThreadLocal
    Bmob用户管理操作
    Textview下划线注册用户跳转实现
    Android中多个调用Activity的问题
    解决android:theme="@android:style/Theme.NoDisplay" 加入这句话后程序不能运行
    友盟自动更新
    友盟消息推送和更新XML配置
    Android 云服务器的搭建和友盟APP自动更新功能的实现
  • 原文地址:https://www.cnblogs.com/cmfwm/p/7646696.html
Copyright © 2011-2022 走看看