AOP 切面判断 token 是否有效

需求:

  1. 接口必须传入 token
  2. token 必须有效
  3. token 未过期

maven 依赖

  • 引入 aop 做切面
  • 引入 hutool 做 JWT 解析
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-core</artifactId>
    <version>${hutool-core.version}</version>
</dependency>

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>${hutool-all.version}</version>
</dependency>

 
关键代码

  • 使用 @Before 在流量进入接口前先检验
  • 获取过期时间戳
  • 过期需要抛出异常
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil; 
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Objects;

@Aspect
@Component
@Slf4j
public class AuthorizationAspect {

    @Before("execution(* com.xxx.controller.*.*(..))")
    public void checkAuthorization(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))).getRequest();
        String authorizationHeader = request.getHeader("Authorization");
        Assert.isTrue(StringUtils.isBlank(authorizationHeader), TokenExpireEnum.NULL);
        Assert.isTrue(isExpireAuthorization(authorizationHeader), TokenExpireEnum.EXPIRE);
    }

    /**
     * 判断token是否过期
     *
     * @param jwtToken 令牌
     * @return 是否过期
     */

    private boolean isExpireAuthorization(String jwtToken) {
        JWT jwt = null;
        try {
            jwt = JWTUtil.parseToken(jwtToken);
        } catch (Exception e) {
            Assert.throwException(TokenExpireEnum.PARSE);
        }

        Object expObj = jwt.getPayload("exp");
        Long exp = Convert.convert(new TypeReference<Long>() {
        }, expObj);
        Instant now = Instant.now();
        Instant timeStampInstant = Instant.ofEpochSecond(exp);
        if (now.isAfter(timeStampInstant)) {
            log.error("token expired, time: {}", timeStampInstant);
            return true;
        }
        return false;
    }
}

 
这样问题来了,登录获取 token 的接口也被拦截调了,两个办法

  1. @Before 可以排除不需要拦截类
  2. 新增注解,在不需要 token 校验的方法加上

这里举例方法二

新建注解 ExcludeAuthorizationCheck

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeAuthorizationCheck {
}

@Before 排除注解 ExcludeAuthorizationCheck

  @Before("execution(* com.xxx.controller.*.*(..)) && !@annotation(com.xxx.ExcludeAuthorizationCheck)")
  
### sa-tokenAOP集成概述 在Java Spring框架中,sa-token可以很好地与面向切面编程(AOP)相结合来实现权限控制和其他横切关注点的功能。通过这种方式,可以在不修改业务逻辑代码的情况下增强功能。 #### 使用sa-token进行身份验证和授权 为了使sa-token能够利用AOP特性,在配置类中定义切入点表达式,这些表达式指定了哪些方法应该被拦截并应用额外的行为。通常情况下,这涉及到创建一个自定义注解用于标记受保护的方法或控制器端点[^1]。 ```java @Aspect @Component public class SaTokenAop { @Autowired private StpInterface stpLogic; /** * 定义切入点, 对所有controller包下的接口进行监控 */ @Pointcut("execution(public * com.example.controller..*.*(..))") public void controllerLayer() {} /** * 切入点执行之前触发该函数 * * @param joinPoint 连接点对象 */ @Before("controllerLayer()") public void doBefore(JoinPoint joinPoint){ // 获取当前请求的token String token = SaHolder.getRequest().getHeader("Authorization"); try { // 验证token有效性 boolean verifyResult = StpUtil.checkLogin(); if (!verifyResult) { throw new NotLoginException("未登录异常!"); } // 可选: 执行更多基于角色或其他条件的身份验证 } catch (NotLoginException e) { // 处理认证失败的情况 ResponseUtil.out(ServletActionContext.getResponse(), Result.error(e.getMessage())); return; } System.out.println("[Sa-Token] >>>> 请求路径:" + ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletPath()); System.out.println("[Sa-Token] >>>> 控制层正常进入..."); } } ``` 此代码片段展示了如何设置`@Aspect`组件以监听特定于控制器层(`com.example.controller`)的所有公共方法调用,并在其前实施安全检查。如果检测到用户尚未登录,则抛出异常阻止进一步处理;否则允许继续访问目标资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值