zoukankan      html  css  js  c++  java
  • 利用基于@AspectJ的AOP实现权限控制

    一. AOP与@AspectJ

           AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程。我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理解为在系统中,我们需要很多次重复实现的功能。比如计算某个方法运行了多少毫秒,判断用户是不是具有访问权限,用户是否已登录,数据的事务处理,日志记录等等。

    AOP的术语

    • 连接点(Joinpoint)

                程序执行的某个特殊位置:比如类开始初始化前,类初始化后,某个方法调用前,调用后等。 连接点 可 以 理解为AOP向目标类织入代码的地方。

    • 切点(Pointcut)

                每一个类都有许多的连接点,所以AOP通过切点来定位特定的连接点。可以通过数据库查询的概念来理解切点和连接点的关系:连接点相当于数据库中的记录,而切点就是查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。

    • 增强(Advice)

                增强就是织入到目标类连接点上的一段代码。它既包含了添加到目标连接点上的一段执行逻辑,也包含了用于定位连接点的方位信息。

            AspectJ是语言级的AOP实现,它扩展了AOP的语法,能够在编辑提供横切代码的织入。@AspectJ是AspecJ1.5新增的功能,它通过JDK5.0的注解技术,允许开发者在POJO中定义切面。

    二. 自定义注解

           因为@AspectJ是基于JDK5.0的注解技术实现,所以我们有必要了解一下注解相关的知识,并学习如何自定义一个注解。

           注解(Annotation)是代码的附属信息,它可以用来修饰类,属性,方法,同时它遵循一个基本原则,注解不能直接干扰程序代码的运行,无论是增加或者删除注解,代码都能正常运行。

    (1)一个简单的注解类

         Java规定使用@interface修饰定义的注解类。一个注解类可以拥有多个成员,成员声明和接口方法声明类似。

       1: package com.wbl.aop;
       2:  
       3: import java.lang.annotation.ElementType;
       4: import java.lang.annotation.Retention;
       5: import java.lang.annotation.RetentionPolicy;
       6: import java.lang.annotation.Target;
       7:  
       8: /**
       9:  * Created by Lulala on 2015/7/15.
      10:  */
      11: @Retention(RetentionPolicy.RUNTIME)         //声明注解的保留期限
      12: @Target(ElementType.METHOD)                 //声明可以使用该注解的目标类型
      13: public @interface UserAccessAnnotation {    //定义注解
      14:     ACCESS value() default ACCESS.LOOK;     //声明注解成员
      15: }

    三. @AspectJ的使用

    Spring采用AspectJ提供的@AspectJ注解类库及相应的解析库,所以需要在项目中导入aspectjweaver.jar类包。

    (1)定义一个切面

       1: import org.aspectj.lang.annotation.Aspect;
       2: import org.aspectj.lang.annotation.Before;
       3: @Aspect         //通过注解将AspectTest标识为一个切面                    
       4: public class AspectTest{
       5:     @Before("execution(* set(..))")                //定义切点和增强类型
       6:     public void before(){                        //增强的横切逻辑
       7:         System.out.println("Aspect before");
       8:     }
       9: }

           首先,在AspectTest类的定义处,标注了一个@Aspect的注解,表示这个类是一个切面,其次在before方法定义处,标注了@Before注解,并为该注解提供了成员值"execution(* set(..))"。@Before注解表示该增强是前置增强,成员值是一个切点表达式,表示在目标类的set方法上织入增强。

    (2)通过配置使用@AspectJ切面

       1: <beans xmlns="http://www.springframework.org/schema/beans"
       2:        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       3:        xmlns:p="http://www.springframework.org/schema/p"
       4:        xmlns:context="http://www.springframework.org/schema/context"
       5:        xmlns:aop="http://www.springframework.org/schema/aop"
       6:        xsi:schemaLocation="http://www.springframework.org/schema/beans
       7:                 http://www.springframework.org/schema/beans/spring-beans.xsd
       8:                 http://www.springframework.org/schema/context
       9:                 http://www.springframework.org/schema/context/spring-context-3.0.xsd
      10:                 http://www.springframework.org/schema/aop
      11:                 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
      12:  
      13:         <aop:aspectj-autoproxy/>
      14:         <bean class="com.wbl.AspectTest"/>

           首先,在配置文件中引入aop的命名空间,然后通过aop命名空间的<aop:aspectj-autoproxy/>自动为Spring容器中那些匹配@AspectJ切面的Bean创建代理,完成自动代理的创建工作。

        <aop:aspectj-autoproxy/>有一个proxy-target-class属性,默认为false,表示使用JDK的动态代理织入增强,当配置为<aop:aspectj-autoproxy proxy-target-class=”true”/>时,表示使用CGLib的动态代理织入增强。
    四. 利用基于@AspectJ的AOP实现权限控制
    (1) 定义一个枚举类
       1: public enum ACCESS {
       2:     LOOK,EXIT,DOWNLOAD,ADMIN
       3: }

    该枚举表示用户拥有的权限,权限由低到高。

    (2)定义一个注解

       1: @Retention(RetentionPolicy.RUNTIME)         //声明注解的保留期限
       2: @Target(ElementType.METHOD)                 //声明可以使用该注解的目标类型
       3: public @interface UserAccessAnnotation {    //定义注解
       4:     ACCESS value() default ACCESS.LOOK;     //声明注解成员
       5: }

    定义好这个注解之后,可以把注解放在需要进行权限控制的方法前

       1: public class DataOperate extends ActioinSupport{
       2:  
       3:     @UserAccessAnnotation(ACCESS.ADMIN)
       4:     public String updateData(String data){
       5:         System.out.println("Updata Data");
       6:     }
       7: }

           在这里我们使用 UserAccessAnnotation 来表示需要在updateData 方法执行之前判断用户的权限是否为管理员权限。

    (3) 定义切点Pointcut

       1: public class SystemArchitecture {
       2:     /**
       3:      * A Join Point is defined in the action layer where the method needs
       4:      * a permission check.
       5:      */
       6:     @Pointcut("@annotation(com.wbl.aop.UserAccessAnnotation)")
       7:     public void userAccess(){}
       8: }

    PointCut 即切入点,就是定义方法执行的点,before表示在方法执行前、after 表示方法执行后或者 around表示方法执行前后。 一般情况下,我们把 PointCut 全部集中定义在 SystemArchitecture 类中,以方便修改和管理。

    (4) 定义一个切面

       1: @Aspect
       2: public class PermissionAspect {
       3:     @Before(value = "com.wbl.aop.SystemArchitecture.userAccess()&&" + 
       4:     "@annotation(userAccessAnnotation)",argNames="userAccessAnnotation")
       5:  
       6:     public void checkPermission(UserAccessAnnotation userAccessAnnotation) throws Exception{
       7:         User user = (User)ActionContext.getContext().getSession().get("user");
       8:         if(user != null){
       9:             if(user.getBehaviorLevel() < userAccessAnnotation.value().ordinal() + 1){
      10:                 throw new NoPermissionException("NO_ACCESS");
      11:             }
      12:         }
      13:     }
      14: }

    argNames="userAccessAnnotation" 的意思是把 Annotation 当做参数传递进来,并判断用户的权限是否足够。如果用户的权限不足以访问该方法,就要抛出 NoPermissionException,通知系统该用户没有权限。其中NoPermissionException是自定义的异常。

       1: public class NoPermissionException extends Exception {
       2:     public NoPermissionException(String msg){
       3:         super(msg);
       4:     }
       5: }

    (5) 在applicationContext.xml中配置切面

       1: <aop:aspectj-autoproxy/>
       2: <bean class="com.wbl.aop.PermissionAspect"/>

    (6) 在Struts中配置全局异常

       1: <global-results> 
       2:  <result name="error">/WEB-INF/jsp/error.jsp</result> 
       3:  </global-results> 
       4:  <global-exception-mappings> 
       5:  <exception-mapping exception="com.wbl.exceptions.NoPermissionException" 
       6:  result="loginerror"/> 
       7:  </global-exception-mappings>
  • 相关阅读:
    矩阵树定理 / 生成树计数
    NC20811 蓝魔法师 (树形DP/树上01背包)
    Xor-MST学习/ 2020牛客暑假多校(五)B.Graph
    HDU-6820 Tree (2020杭电多校(五) 1007)
    Flipping Coins (概率DP)
    宝石装箱 容斥+dp
    Rabbit的工作(1) (dP)
    Codeforces-1350 E.Orac and Game of Life
    HDU-6563 Strength (贪心)
    HDU-6558 The Moon (期望DP)
  • 原文地址:https://www.cnblogs.com/bloodhunter/p/4662534.html
Copyright © 2011-2022 走看看