package com.daqi.login.demo.utils;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.xml.bind.DatatypeConverter;
import java.net.InetAddress;
import java.util.*;
/**
* User: ldj
* Date: 2023/3/17
* Time: 18:23
* Description: JWT工具类,读取配置文件防止出现乱码,编码统一设置成UTF-8
*/
@Slf4j
@Component
@ConfigurationProperties(prefix = "spring.jwt.properties")
public class JwtUtil {
private static String issuer;
private static String secretKey;
private static String subject;
/*
* @ConfigurationProperties只认非静态set方法,
* @Data根据成员变量的修饰符生成对映修饰的get/set方法
* 所以需要手动写非静态的set方法
*/
public void setIssuer(String issuer) {
JwtUtil.issuer = issuer;
}
public void setSecretKey(String secretKey) {
JwtUtil.secretKey = secretKey;
}
public void setSubject(String subject) {
JwtUtil.subject = subject;
}
/**
* 常用方法
* 校验令牌 (能解析出来就是不过期的,可用的,返回true)
*/
public static Boolean validateToken(String token) {
Claims claims = parseToken(token);
return claims != null;
}
/**
* 常用方法
* 构建jwt令牌
* @param claims map<k,v> 令牌数据载体,一般是存放用户的权限/角色等信息
*/
public static String constructToken(Map<String, Object> claims, Integer exprTime) {
JwtBuilder builder = Jwts.builder();
try {
InetAddress inetAddress = InetAddress.getLocalHost();
String hostName = inetAddress.getHostName();
String hostAddress = inetAddress.getHostAddress();
builder.setAudience("[" + hostName + "]::" + "[" + hostAddress + "]");
} catch (Exception e) {
builder.setAudience("[/]");
log.warn(e.getMessage());
}
builder.setId(UUID.randomUUID().toString().replaceAll("-", ""));
Map<String, Object> header = new LinkedHashMap<>();
header.put(Header.TYPE, Header.JWT_TYPE);
builder.setHeaderParams(header); //头部
builder.setIssuer(issuer); //令牌颁发者
builder.setSubject(subject); //主题:描述令牌的信息
builder.setClaims(claims); //数据载体
long nowMillis = System.currentTimeMillis();
builder.setIssuedAt(new Date(nowMillis)); //签发时间
//如果没设置过期时间,默认30分钟
if (exprTime == null) {
builder.setExpiration(new Date(nowMillis + 30 * 60 * 1000));
} else {
builder.setExpiration(new Date(nowMillis + exprTime * 60 * 1000));
}
//使用HS256算法生成签名 signature: HS256[Base64(head) + Base64(payload) + Base64(secret)]
//builder.signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)));
builder.signWith(SignatureAlgorithm.HS256, DatatypeConverter.parseBase64Binary(secretKey));
return builder.compact();
}
/**
* 常用方法
* 解析令牌
*/
public static Claims parseToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey)).parseClaimsJws(token).getBody();
} catch (Exception e) {
log.error("[JwtUtil] token无法被解析! Cause:[{}]", e.getMessage());
}
return claims;
}
/**
* 获取token的剩余过期时间
*/
public static long getTokenRemainingTime(String token) {
long remainingTime = 0;
try {
Claims claims = parseToken(token);
if (!CollectionUtils.isEmpty(claims)) {
Date expiration = claims.getExpiration();
if (Objects.nonNull(expiration)) {
remainingTime = expiration.getTime() - System.currentTimeMillis();
}
}
} catch (Exception e) {
log.error("error:{}", e.getMessage());
}
return remainingTime;
}
/**
* 刷新token
*/
public static String refreshToken(String oldToken, Map<String, Object> claims) {
String refreshedToken = null;
try {
if (CollectionUtils.isEmpty(claims)) {
Claims oldClaims = parseToken(oldToken);
if (!CollectionUtils.isEmpty(oldClaims)) {
claims = oldClaims;
refreshedToken = constructToken(claims, null);
}
}
} catch (Exception e) {
log.error("error:{}", e.getMessage());
}
return refreshedToken;
}
}
spring.jwt.properties.issuer=ldj
spring.jwt.properties.secretKey=helloKitty
spring.jwt.properties.subject=jwt测试
@Test
void testCreateJwt() throws IOException {
User user = new User();
user.setId(155658988L);
user.setName("ldj");
user.setPhone("1355877544");
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
String json = JacksonUtil.writeValueAsString(user);
Map map = JacksonUtil.readValue(json, Map.class);
String token = JwtUtil.constructToken(map, null);
System.out.println(token);
}
@Test
void testParseJwt() throws IOException {
String jwt = "粘贴生成的加密字符串";
Claims claims = JwtUtil.parseToken(jwt);
System.out.println(JacksonUtil.writeValueAsString(claims));
}