JWT生成tonken验证+AOP拦截验证

JSON Web Token(JWT)是目前都在用的前后分离跨域验证规则。

JWT由3部分组成

  • Header——头部一般Base64URL编码,作用:声明token类型,声明token使用的加密算法。一般都是使用HMAC-SHA256或者RSA支持很多种算法(HS256、HS384、HS512、RS256、RS384、RS512、ES256、ES384、ES512、PS256、PS384)
  • PayLoad——载荷(自定义数据)也叫消息体(payload)是一个JSON对象。一般Base64URL编码。存储用户信息,过期时间等等。。。因为载荷里面包含可以包含许多用户自定义信息,所以后端不用再频繁的与数据库进行交互,可以直接获取信息。但是这也导致载荷里不建议储存敏感信息,因为可以直接Base64URL解密就能看到了,当然你也可以额外再加密。  这些有效信息包含三个部分:标准中注册的声明、公共的声明和私有的声明
  • Signature(签名其实是由Header+PayLoad+自定义密钥再由加密算法(HS256)或者其他算法生成。这也是jwt安全的真正原因)

1、引入依赖pom.xml

        
        
            com.auth0
            java-jwt
            3.8.2
        

2、编写jwt工具类JwtUtil.java

package com.muchuantong.util;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

/**
 * @Author: Zou Tiancong
 * @Date: 2021/12/1 0001 10:37
 * @Annotation:jwtToken
 */
public class JwtUtil {

	// 设置过期时间
	private static final long EXPIRE_DATE = 60*1000;
	// token秘钥
	private static final String TOKEN_SECRET = "TEST-AUTH-TOKEN";

	// 实现签名方法
	public static String token(String id, String openId, String nickName) {

		String token = "";
		try {
			// 这里将用户存入了Token,在下面的解析中,也会有解析的方法可以获取到Token里面的数据
			// Token过期的时间
			Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_DATE);
			// 秘钥及加密算法
			Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
			// 设置头部信息,类型以及签名所用的算法
			Map header = new HashMap<>();
			header.put("typ", "JWT");
			header.put("alg", "HS256");
			// 携带用户信息,存入token,生成签名
			token = JWT.create()
					.withHeader(header) //设置头部信息Header
					.withIssuer("TEST") //设置签名是由谁生成
					.withSubject("AUTH-TOKEN") //设置签名的主题
					.withAudience(nickName) //设置签名的观众
					.withIssuedAt(new Date()) //设置生成签名的时间
					.withExpiresAt(expireDate) //设置签名过期的时间
					.withClaim("id", id) //自定义信息
					.withClaim("openId", openId)//自定义信息
					.withClaim("nickName", nickName)//自定义信息
					.withJWTId(id) //jwt的id,主要用来作为一次性token,从而回避重放攻击
					.sign(algorithm);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return token;
	}

	// 验证token
	public static boolean verify(String token) {
		/**
		 * @desc 验证token,通过返回true
		 * @params [token]需要校验的串
		 **/
		try {
			Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
			JWTVerifier verifier = JWT.require(algorithm).build();
			DecodedJWT jwt = verifier.verify(token);
			String subject = jwt.getSubject();
			List audience = jwt.getAudience();
			Map claims = jwt.getClaims();
			System.out.println(subject+"*******"+audience);
			for (Map.Entry entry : claims.entrySet()){
				String key = entry.getKey();
				Claim claim = entry.getValue();
				String value = claim.asString();
				System.out.println("key:"+key+" value:"+value);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Token已过期,需要重新登录");
		}
		return false;
	}

	// 生成token
	public static String setToken(String id, String openId, String nickName) {
		String token = token(id, openId, nickName);
		return token;
	}

}

2、自定义注解接口Auth.java

package com.muchuantong.util;

import java.lang.annotation.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: ZouTiancong
 * @Date: 2022/05/23/22:37
 * @Description:
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Auth {
    boolean token() default true;
}

3、自定义注解APO实现类AuthAspect.java

package com.muchuantong.util;

import javax.servlet.http.HttpServletRequest;

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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: ZouTiancong
 * @Date: 2022/05/23/22:39
 * @Description:
 */
@Component
@Aspect
public class AuthAspect {
	@Autowired
	private HttpServletRequest request;

	@Pointcut("@annotation(com.muchuantong.util.Auth)")
	private void authPointcut() {
	}

	@Around("authPointcut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		// 获取方法签名信息从而获取方法名和参数类型
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

		// 获取目标方法对象上注解中的属性值
		Auth auth = methodSignature.getMethod().getAnnotation(Auth.class);

		// 校验签名
		if (auth.token()) {
			boolean token = JwtUtil.verify(request.getHeader("token"));
			// 如果token校验失败返回
			if (!token) {
				return new Result<>("401", "token已过期,请重新登录!");
			}
		}
		return joinPoint.proceed();
	}
}

4、在需要token验证的地方加入注解@Auth

JWT生成tonken验证+AOP拦截验证_第1张图片

 5、前端调用查看效果,token生成返回成功,后端也能成功读取数据

JWT生成tonken验证+AOP拦截验证_第2张图片

JWT生成tonken验证+AOP拦截验证_第3张图片

你可能感兴趣的:(Java,json)