一、前言:
Java开发中有很多登录Token解决方案 下面我给大家总结如何使用SpringAop实现简单Token拦截
二、相关依赖Maven:
<!--鉴权-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- aop 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.4.1</version>
</dependency>
三、实际代码:
JWT工具类:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.Objects;
/**
* @author zhu
* @date 2021/6/1 14:49
* JWT工具类
*/
public class JwtUtil {
/**
* 有效期为60 * 60 *1000 一个小时
*/
public static final Long JWT_TTL = 3600000L;
/**
* 设置秘钥明文
*/
public static final String JWT_KEY = "njcool";
/**
* 创建token
*
* @param id 唯一标识
* @param subject 主题
* @param ttlMillis 时间
* @return token
*/
public static String createJWT(String id, String subject, Long ttlMillis) {
//获取当前系统时间
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (Objects.isNull(ttlMillis)) {
ttlMillis = JwtUtil.JWT_TTL;
}
//设置过期时间
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
SecretKey secretKey = generalKey();
//创建Token
JwtBuilder builder = Jwts.builder()
//唯一的ID
.setId(id)
// 主题 可以是JSON数据
.setSubject(subject)
// 签发者
.setIssuer("admin")
// 签发时间
.setIssuedAt(now)
//使用HS256对称加密算法签名, 第二个参数为秘钥
.signWith(SignatureAlgorithm.HS256, secretKey)
// 设置过期时间
.setExpiration(expDate);
return builder.compact();
}
/**
* 生成加密后的秘钥 secretKey
*
* @return 针对秘钥进行二次加密
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
}
/**
* 解析
*
* @param jwt token
* @return parseJWT
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
//测试生成Token
public static void main(String[] args) {
String jwt = JwtUtil.createJWT("1", "3333", null);
System.out.println(jwt);
}
}
LoginAop拦截:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @author zhu
* @date 2021/7/28 15:22
* Aop 登录拦截器
*/
@Slf4j
@Aspect
@Component
public class HttpAspect {
/**
* 登录路径 ->放行
*/
private static final String LOGIN = "login";
/**
* @Pointcut 声明切入点表达式。
* 注意此处扫描的是你的Controller层接口位置
*/
@Pointcut("execution(public * com.zhu.controller..*..*(..))")
public void pointcut() {
}
/**
* @Around 环绕通知
* @Around("pointcut()") 可以理解为对这个方法进行环绕通知
* ProceedingJoinPoint 参数 用于环绕通知,
* 使用proceed()方法来执行目标方法,可以理解为 前置通知结束 开始执行使用该注解的方法。
*/
@Around("pointcut()")
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert attributes != null;
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("Authorization");
if (request.getRequestURI().contains(LOGIN)) {
return joinPoint.proceed();
}
if (StringUtils.isNotBlank(token)) {
try {
JwtUtil.parseJWT(token);
} catch (Exception e) {
// 解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现 401
log.info("AuthorizeFilter 解析jwt令牌出错", e);
//此处可以返回自定义 Result结果对象 转成Json格式
return JsonUtil.format("解析jwt令牌出错");
}
} else {
log.info("AuthorizeFilter 登录令牌不存在");
return JsonUtil.format(" 登录令牌不存在");
}
//执行业务逻辑,放行
return joinPoint.proceed();
}
}
四、PostMan使用:
登录接口应该放行So: