package com.rongyichuang.auth.util; import io.jsonwebtoken.*; import io.jsonwebtoken.security.Keys; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Date; /** * JWT工具类 */ @Component public class JwtUtil { private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class); @Value("${app.jwt.secret}") private String jwtSecret; @Value("${app.jwt.expiration:86400000}") // 默认24小时 private long jwtExpiration; /** * 生成JWT token(旧版本,保持兼容性) */ public String generateToken(Long userId, String phone) { return generateToken(userId, phone, null); } /** * 生成JWT token(新版本,支持wxopenid) */ public String generateToken(Long userId, String phone, String wxopenid) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + jwtExpiration); SecretKey key = getSigningKey(); JwtBuilder builder = Jwts.builder() .setSubject(userId.toString()) .setIssuedAt(now) .setExpiration(expiryDate); // 只有当phone不为null时才添加phone claim if (phone != null) { builder.claim("phone", phone); } // 只有当wxopenid不为null时才添加wxopenid claim if (wxopenid != null) { builder.claim("wxopenid", wxopenid); } return builder.signWith(key, SignatureAlgorithm.HS256).compact(); } /** * 根据配置的密钥生成满足 HMAC-SHA 要求的签名密钥: * - 若明文密钥长度不足 256 bit,使用 SHA-256 衍生为 256-bit * - 保持对现有 app.jwt.secret 的兼容,不修改配置键名或其它逻辑 */ private SecretKey getSigningKey() { try { byte[] keyBytes = jwtSecret.getBytes(StandardCharsets.UTF_8); if (keyBytes.length < 32) { MessageDigest digest = MessageDigest.getInstance("SHA-256"); keyBytes = digest.digest(keyBytes); } if (keyBytes.length < 32) { byte[] padded = new byte[32]; System.arraycopy(keyBytes, 0, padded, 0, Math.min(keyBytes.length, 32)); keyBytes = padded; } return new SecretKeySpec(keyBytes, "HmacSHA256"); } catch (Exception e) { throw new RuntimeException("初始化JWT签名密钥失败", e); } } /** * 从token中获取用户ID */ public Long getUserIdFromToken(String token) { Claims claims = getClaimsFromToken(token); return Long.parseLong(claims.getSubject()); } /** * 从token中获取手机号 */ public String getPhoneFromToken(String token) { Claims claims = getClaimsFromToken(token); return claims.get("phone", String.class); } /** * 从token中获取微信openid */ public String getWxOpenidFromToken(String token) { Claims claims = getClaimsFromToken(token); return claims.get("wxopenid", String.class); } /** * 验证token是否有效 */ public boolean validateToken(String token) { try { getClaimsFromToken(token); return true; } catch (JwtException | IllegalArgumentException e) { logger.error("JWT token验证失败: {}", e.getMessage()); return false; } } /** * 检查token是否过期 */ public boolean isTokenExpired(String token) { try { Claims claims = getClaimsFromToken(token); return claims.getExpiration().before(new Date()); } catch (JwtException | IllegalArgumentException e) { return true; } } /** * 从token中解析Claims */ private Claims getClaimsFromToken(String token) { SecretKey key = getSigningKey(); return Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); } }