SpringAOP01 利用AOP实现权限验证、利用权限验证服务实现权限验证

 

1 编程范式

  1.1 面向过程

  1.2 面向对象

  1.3 面向切面编程

  1.4 函数式编程

  1.5 事件驱动编程

 

2 什么是面向切面编程

  2.1 是一种编程范式,而不是一种编程语言

  2.2 解决一些特定的问题

  2.3 做为面向对象编程的一种补充

 

3  AOP产生的初衷

  3.1 解决代码重复性问题 Don't Repeat Yourself

  3.2 解决关注点分离问题 Separation of Concerns

    3.2.1 水平分离(技术上划分)

      控制层 -> 服务层 -> 持久层java

    3.2.2 垂直分离(模块上划分)

      模块划分git

    3.2.3 切面分离(功能上划分)

      分离功能性需求和非功能性需求spring

 

4 使用AOP的好处

  4.1 集中处理某一个关注点、横切逻辑

  4.2 能够很方便地添加、删除关注点

  4.3 侵入性减小,加强代码可读性和可维护性

  

5 AOP的使用场景

  5.1 权限控制

  5.2 缓存控制

  5.3 事物控制

  5.4 审计日志

  5.5 性能监控

  5.6 分布式追踪

  5.7 异常处理

  

6 利用传统方法实现权限验证

  6.1 建立一个springBoot项目

    下载地址:点击前往编程

  6.2 新建一个Product实体类

package cn.test.demo.base_demo.entity; /** * @author 王杨帅 * @create 2018-04-29 17:11 * @desc 商品实体类 **/
public class Product { private Integer id; private String name; public Product() { } public Product(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}'; } }
Product.java

  6.3 新建一个权限模拟类

    该类主要用来设定用户和获取用户缓存

package cn.test.demo.base_demo.security; /** * @author 王杨帅 * @create 2018-04-29 17:15 * @desc 模拟用户登陆,该类能够设定用户和获取用户 **/
public class CurrentSetHolder { private final static ThreadLocal<String> holder = new ThreadLocal<>(); /** * 获取用户 * @return
     */
    public static String get() { return holder.get() == null ? "unknown" : holder.get(); } /** * 设定用户 * @param user */
    public static void set(String user) { holder.set(user); } }
CurrentSetHolder.java

  6.4 新建一个权限校验类

    该类主要用于判断当前用户是不是“admin”用户编程语言

package cn.test.demo.base_demo.service; import cn.test.demo.base_demo.security.CurrentSetHolder; import org.springframework.stereotype.Component; /** * @author 王杨帅 * @create 2018-04-29 17:19 * @desc 权限校验服务类 **/ @Component public class AuthService { /** * 权限检查,若是用户不是 “admin" 就会报错 */
    public void checkAccess() { String user = CurrentSetHolder.get(); if (!"admin".equals(user)) { throw new RuntimeException("operation not allow."); } } }
AuthService.java

  6.5 新建ProductService类

    该类主要实现对Product的一些操做分布式

package cn.test.demo.base_demo.service; import cn.test.demo.base_demo.entity.Product; import cn.test.demo.base_demo.security.AdminOnly; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author 王杨帅 * @create 2018-04-29 17:14 * @desc 商品服务层 **/ @Service @Slf4j public class ProductService { private final String className = getClass().getName(); /** * 依赖注入权限校验服务 */ @Autowired private AuthService authService; public void insert(Product product) { authService.checkAccess(); // 利用权限校验对象进行权限校验,不是 ”admin" 就会报错
        log.info("===/" + className + "/insert===新增数据"); } @AdminOnly public void delete(Integer id) { // authService.checkAccess(); // 利用权限校验对象进行权限校验
        log.info("===/" + className + "/delete===删除数据"); } }
ProductService.java

  6.6 建立一个服务层测试类

    在调用ProductService的insert方法前对用户进行设定ide

package cn.test.demo.base_demo.service; import cn.test.demo.base_demo.entity.Product; import cn.test.demo.base_demo.security.CurrentSetHolder; import org.junit.Test; import org.junit.runner.RunWith; import org.omg.CORBA.Current; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest public class ProductServiceTest { /** * 依赖注入权限 */ @Autowired private ProductService productService; /** * productService.insert(product) 方法中有权限验证,若是不是“admin"用户就会报错 */ @Test public void annonInsert() { CurrentSetHolder.set("bob"); // 设置用户
        Product product = new Product(); productService.insert(product); } /** * productService.insert(product) 方法中有权限验证,若是不是“admin"用户就会报错 */ @Test public void adminInsert() { CurrentSetHolder.set("admin"); // 设置用户
        Product product = new Product(); productService.insert(product); } @Test public void delete() throws Exception { } }
ProductServiceTest.java

 

7 利用AOP实现权限验证

  7.1 新建一个springBoot项目

    下载地址:点击前往函数式编程

  7.2 建立一个Product实体类

package cn.test.demo.base_demo.entity; /** * @author 王杨帅 * @create 2018-04-29 17:11 * @desc 商品实体类 **/
public class Product { private Integer id; private String name; public Product() { } public Product(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}'; } }
Product.java

  7.3 建立一个AdminOnly注解

package cn.test.demo.base_demo.security; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AdminOnly { }
AdminOnly.java

  7.4 新建一个权限模拟类

    该类主要用来设置用户和获取用户函数

package cn.test.demo.base_demo.security; /** * @author 王杨帅 * @create 2018-04-29 17:15 * @desc 模拟用户登陆,该类能够设定用户和获取用户 **/
public class CurrentSetHolder { private final static ThreadLocal<String> holder = new ThreadLocal<>(); /** * 获取用户 * @return
     */
    public static String get() { return holder.get() == null ? "unknown" : holder.get(); } /** * 设定用户 * @param user */
    public static void set(String user) { holder.set(user); } }
CurrentSetHolder.java

  7.5 建立一个切面类

    该类主要对全部使用了@AdminOnly注解的方法进行权限校验

package cn.test.demo.base_demo.security; import cn.test.demo.base_demo.service.AuthService; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author 王杨帅 * @create 2018-04-29 17:37 * @desc 权限检查的AOP类 **/ @Aspect @Component public class SecurityAspect { @Autowired AuthService authService; @Pointcut("@annotation(AdminOnly)") public void adminOnly(){ } @Before("adminOnly()") public void check(){ authService.checkAccess(); } }
SecurityAspect.java

  7.6 新建一个ProductService服务类

    该类的delete方法用了@AdminOnly注解,因此delete方法会进行权限校验

package cn.test.demo.base_demo.service; import cn.test.demo.base_demo.entity.Product; import cn.test.demo.base_demo.security.AdminOnly; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author 王杨帅 * @create 2018-04-29 17:14 * @desc 商品服务层 **/ @Service @Slf4j public class ProductService { private final String className = getClass().getName(); /** * 依赖注入权限校验服务 */ @Autowired private AuthService authService; public void insert(Product product) { authService.checkAccess(); // 利用权限校验对象进行权限校验,不是 ”admin" 就会报错
        log.info("===/" + className + "/insert===新增数据"); } @AdminOnly public void delete(Integer id) { // authService.checkAccess(); // 利用权限校验对象进行权限校验
        log.info("===/" + className + "/delete===删除数据"); } }
ProductService.java

  7.7 建立一个测试类

    productService.delete(id) 方法中有权限验证,若是不是“admin"用户就会报错【利用AOP实现的】

package cn.test.demo.base_demo.service; import cn.test.demo.base_demo.entity.Product; import cn.test.demo.base_demo.security.CurrentSetHolder; import org.junit.Test; import org.junit.runner.RunWith; import org.omg.CORBA.Current; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest public class ProductServiceTest { /** * 依赖注入权限 */ @Autowired private ProductService productService; /** * productService.insert(product) 方法中有权限验证,若是不是“admin"用户就会报错【利用传统方法实现的】 */ @Test public void annonInsert() { CurrentSetHolder.set("bob"); // 设置用户
        Product product = new Product(); productService.insert(product); } /** * productService.insert(product) 方法中有权限验证,若是不是“admin"用户就会报错【利用传统方法实现的】 */ @Test public void adminInsert() { CurrentSetHolder.set("admin"); // 设置用户
        Product product = new Product(); productService.insert(product); } /** * productService.delete(id) 方法中有权限验证,若是不是“admin"用户就会报错【利用AOP实现的】 */ @Test public void annoDelete() throws Exception { CurrentSetHolder.set("peter"); productService.delete(3); } /** * productService.delete(id) 方法中有权限验证,若是不是“admin"用户就会报错【利用AOP实现的】 */ @Test public void adminDelete() { CurrentSetHolder.set("admin"); productService.delete(4); } }
ProductServiceTest.java

  7.8 源代码

    点击前往