需求:
- 接口必须传入 token
- token 必须有效
- 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 的接口也被拦截调了,两个办法
- @Before 可以排除不需要拦截类
- 新增注解,在不需要 token 校验的方法加上
这里举例方法二
新建注解 ExcludeAuthorizationCheck
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeAuthorizationCheck {
}
@Before 排除注解 ExcludeAuthorizationCheck
@Before("execution(* com.xxx.controller.*.*(..)) && !@annotation(com.xxx.ExcludeAuthorizationCheck)")