package xin.merlin.myplayerbackend.utils; import io.jsonwebtoken.*; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import xin.merlin.myplayerbackend.config.security.JwtProperties; import javax.crypto.SecretKey; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.UUID; @Component @RequiredArgsConstructor public class JwtUtil { private final JwtProperties jwtProperties; private SecretKey key; private JwtParser jwtParser; @PostConstruct public void init() { try { // 从配置文件密钥生成 SecretKey this.key = Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8)); this.jwtParser = Jwts.parser() .verifyWith(key) .build(); } catch (Exception e) { throw new RuntimeException("JWT 密钥初始化失败,请检查配置文件 jwt.secret", e); } } /** * 生成 JWT Token */ public String generateToken(String uAccount, Integer uId) { Date now = new Date(); Date expireDate = new Date(now.getTime() + jwtProperties.getExpire() * 1000L); return Jwts.builder() .subject(uAccount) .claim("id", uId) .claim("account", uAccount) .id(UUID.randomUUID().toString()) .issuedAt(now) .expiration(expireDate) .issuer(jwtProperties.getIssuer()) .signWith(key, Jwts.SIG.HS256) // JJWT 0.12.6推荐的写法 .compact(); } /** * 解析 Token 获取 Claims */ public Claims getClaims(String token) { try { Jws jws = jwtParser.parseSignedClaims(token); System.out.println(jws.getPayload()); return jws.getPayload(); } catch (ExpiredJwtException e) { throw new TokenExpiredException("Token 已过期", e); } catch (JwtException e) { throw new InvalidTokenException("无效的 Token", e); } catch (Exception e) { throw new InvalidTokenException("解析 Token 失败", e); } } /** * 判断 Token 是否过期 */ public boolean isTokenExpired(String token) { Claims claims = getClaims(token); return claims.getExpiration().before(new Date()); } /** * 获取账号 */ public String getUAccount(String token) { Claims claims = getClaims(token); return claims.getSubject(); } /** * 获取用户ID */ public String getUId(String token) { Claims claims = getClaims(token); return claims.get("id", String.class); } // 自定义异常类 public static class TokenExpiredException extends RuntimeException { public TokenExpiredException(String message, Throwable cause) { super(message, cause); } } public static class InvalidTokenException extends RuntimeException { public InvalidTokenException(String message, Throwable cause) { super(message, cause); } } }