SpringBoot - AOP 实现登录状态检查

前言

记录下AOP实现登录状态的检查,文章使用的JWT校验参考:SpringBoot - 集成Auth0 JWT


实现登录状态检查的方式

  • Servlet过滤器
  • 拦截器
  • Spring AOP

AOP 定义

AOP(Aspect Oriented Programming),面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术,在程序开发中主要用来解决一些系统层面上的问题,在不改变原有的逻辑的基础上,增加一些额外的功能,如日志,事务,权限等


AOP 相关概念

术语 概念 描述
Aspect 切面 通知和切点的集合
Joint point 连接点 应用执行过程中能够插入切面的一个点
Advice 通知 定义切面是什么以及何时使用
Pointcut 切点 定义切面在何处执行,切点的定义会匹配通知所有要织入的连接点
Weaving 织入 把切面应用到目标对象并创建新的代理代理对象的过程

Advice 通知类型

术语 概念 描述
Before 前置通知 在目标方法被调用之前调用通知功能
After 后置通知 在目标方法完成之后调用,此时不关心方法的输出是什么
AfterReturning 返回通知 在目标方法成功执行之后调用通知
AfterThrowing 异常通知 在目标方法抛出异常后调用通知
Around 环绕通知 通知包裹了通知的方法,在被通知的方法调用之前和调用之后执行自定义行为

具体实现

实现代码

  • 自定义注解CheckLogin
/**
 * @Description 登录校验注解
 * @author coisini
 * @date Oct 14, 2021
 * @Version 1.0
 */
public @interface CheckLogin {
}
  • 切面CheckLoginAspect
import com.coisini.aop.util.JwtUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

/**
 * @Description 登录校验切面
 * @author coisini
 * @date Oct 14, 2021
 * @Version 1.0
 */
@Aspect
@Component
public class CheckLoginAspect {

    /**
     * 只要加了@CheckLogin的方法都会走到这里
     * @param point
     * @return
     */
    @Around("@annotation(com.coisini.aop.auth.annotation.CheckLogin)")
    public Object checkLogin(ProceedingJoinPoint point) {
        try {
            // 从header中获取token
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
            HttpServletRequest request = attributes.getRequest();

            String token = request.getHeader("token");

            // 校验token是否合法
            Boolean valid = JwtUtil.verifyToken(token);
            if (!valid) {
                throw new ServerErrorException(HttpStatus.UNAUTHORIZED.value(), "Token 不合法");
            }

            // 执行后续的方法
            return point.proceed();
        } catch (Throwable throwable) {
            throw new ServerErrorException(HttpStatus.UNAUTHORIZED.value(), "Token 不合法");
        }
    }
}
  • 自定义异常ServerErrorException
import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @Description 自定义异常
 * @author coisini
 * @date Oct 14, 2021
 * @Version 1.0
 */
@Data
@AllArgsConstructor
public class ServerErrorException extends RuntimeException{

    public Integer code;
    public String message;

}
  • 统一异常处理GlobalExceptionAdvice
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @Description 统一异常处理
 * @author coisini
 * @date Oct 14, 2021
 * @Version 1.0
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionAdvice {

    @ExceptionHandler(ServerErrorException.class)
    public ResponseEntity<UnifyMessage> handleServerErrorException(ServerErrorException e) {

        log.warn("ServerErrorException 异常", e);

        return new ResponseEntity<>(
                UnifyMessage.builder()
                        .code(e.getCode())
                        .message(e.getMessage())
                        .build(),
                HttpStatus.UNAUTHORIZED
        );
    }

}
  • 统一消息返回UnifyMessage
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Description 统一消息返回
 * @author coisini
 * @date Oct 14, 2021
 * @Version 1.0
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UnifyMessage {

    private int code;
    private String message;

}

测试

  • 测试方法TestController
/**
 * AOP校验请求头中的Token
 * @return
 */
@CheckLogin
@GetMapping(value = "/test")
public String testCheckLogin() {
    // TODO 业务
    return "Token验证通过";
}
  • 获取Token

在这里插入图片描述


  • Token测试

在这里插入图片描述


  • 传递Token

在这里插入图片描述



源码

GitHubhttps://github.com/maggieq8324/java-learn-demo/tree/master/springboot-aop


- End -
白嫖有风险
点赞加收藏
posted @ 2021-10-14 11:46  Maggieq8324  阅读(429)  评论(0编辑  收藏  举报