|
@@ -1,77 +1,84 @@
|
|
|
package com.zjrs.zwnw.auth.util;
|
|
package com.zjrs.zwnw.auth.util;
|
|
|
|
|
|
|
|
import io.jsonwebtoken.*;
|
|
import io.jsonwebtoken.*;
|
|
|
|
|
+import io.jsonwebtoken.security.Keys;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
+import javax.crypto.SecretKey;
|
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
|
+import java.time.Instant;
|
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * JWT 工具类(HMAC-SHA256)
|
|
|
|
|
- * 使用 jjwt 0.9.1 API
|
|
|
|
|
|
|
+ * JWT 工具类 - 适配 Spring Boot 3.5 & JJWT 0.12+
|
|
|
*/
|
|
*/
|
|
|
@Component
|
|
@Component
|
|
|
public class JwtUtil {
|
|
public class JwtUtil {
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
|
|
private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
|
|
|
|
|
|
|
|
- /** Token 有效期:4小时(秒) */
|
|
|
|
|
|
|
+ /** Token 有效期:4小时 */
|
|
|
private static final long EXPIRE_SECONDS = 4 * 60 * 60;
|
|
private static final long EXPIRE_SECONDS = 4 * 60 * 60;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * HMAC 密钥(生产环境应从配置文件读取)
|
|
|
|
|
|
|
+ * HMAC 密钥
|
|
|
|
|
+ * 注意:HS256 要求密钥长度至少为 256 位(32 字节)
|
|
|
*/
|
|
*/
|
|
|
- private static final String SECRET = "zjrs-zwnw-service-2019-auth-key-xK9mP3qR7vZ1nL5wY8eA";
|
|
|
|
|
|
|
+ private static final String SECRET_STR = "zjrs-zwnw-service-2019-auth-key-xK9mP3qR7vZ1nL5wY8eA";
|
|
|
|
|
+
|
|
|
|
|
+ // 预先构建 SecretKey 对象,性能更好且符合安全规范
|
|
|
|
|
+ private final SecretKey key = Keys.hmacShaKeyFor(SECRET_STR.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 生成 JWT Token
|
|
* 生成 JWT Token
|
|
|
*/
|
|
*/
|
|
|
public String generateToken(String loginId, String userName, String operid, Long operunitid) {
|
|
public String generateToken(String loginId, String userName, String operid, Long operunitid) {
|
|
|
- Map<String, Object> claims = new HashMap<>();
|
|
|
|
|
- claims.put("loginId", loginId);
|
|
|
|
|
- claims.put("userName", userName);
|
|
|
|
|
- claims.put("operid", operid);
|
|
|
|
|
- claims.put("operunitid", operunitid);
|
|
|
|
|
-
|
|
|
|
|
- Date now = new Date();
|
|
|
|
|
- Date expiry = new Date(now.getTime() + EXPIRE_SECONDS * 1000L);
|
|
|
|
|
|
|
+ Instant now = Instant.now();
|
|
|
|
|
+ Instant expiry = now.plusSeconds(EXPIRE_SECONDS);
|
|
|
|
|
|
|
|
return Jwts.builder()
|
|
return Jwts.builder()
|
|
|
- .setClaims(claims)
|
|
|
|
|
- .setSubject(loginId)
|
|
|
|
|
- .setIssuedAt(now)
|
|
|
|
|
- .setExpiration(expiry)
|
|
|
|
|
- .signWith(SignatureAlgorithm.HS256, SECRET.getBytes())
|
|
|
|
|
|
|
+ .header().add("typ", "JWT").and() // 显式指定类型
|
|
|
|
|
+ .subject(loginId)
|
|
|
|
|
+ .claims(Map.of(
|
|
|
|
|
+ "loginId", loginId,
|
|
|
|
|
+ "userName", userName,
|
|
|
|
|
+ "operid", operid,
|
|
|
|
|
+ "operunitid", operunitid
|
|
|
|
|
+ ))
|
|
|
|
|
+ .issuedAt(Date.from(now))
|
|
|
|
|
+ .expiration(Date.from(expiry))
|
|
|
|
|
+ .signWith(key) // 0.12+ 自动识别算法
|
|
|
.compact();
|
|
.compact();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 解析 Token,失败返回 null
|
|
|
|
|
|
|
+ * 解析 Token
|
|
|
*/
|
|
*/
|
|
|
public Claims parseToken(String token) {
|
|
public Claims parseToken(String token) {
|
|
|
try {
|
|
try {
|
|
|
return Jwts.parser()
|
|
return Jwts.parser()
|
|
|
- .setSigningKey(SECRET.getBytes())
|
|
|
|
|
- .parseClaimsJws(token)
|
|
|
|
|
- .getBody();
|
|
|
|
|
|
|
+ .verifyWith(key) // 替换 setSigningKey
|
|
|
|
|
+ .build()
|
|
|
|
|
+ .parseSignedClaims(token) // 替换 parseClaimsJws
|
|
|
|
|
+ .getPayload(); // 替换 getBody
|
|
|
} catch (ExpiredJwtException e) {
|
|
} catch (ExpiredJwtException e) {
|
|
|
log.warn("Token 已过期: {}", e.getMessage());
|
|
log.warn("Token 已过期: {}", e.getMessage());
|
|
|
} catch (JwtException e) {
|
|
} catch (JwtException e) {
|
|
|
- log.warn("Token 解析失败: {}", e.getMessage());
|
|
|
|
|
|
|
+ log.error("Token 校验失败: {}", e.getMessage());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("Token 解析发生未知错误", e);
|
|
|
}
|
|
}
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 校验 Token 是否有效 */
|
|
|
|
|
public boolean isValid(String token) {
|
|
public boolean isValid(String token) {
|
|
|
return parseToken(token) != null;
|
|
return parseToken(token) != null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 获取 Token 有效期(秒) */
|
|
|
|
|
public long getExpireSeconds() {
|
|
public long getExpireSeconds() {
|
|
|
return EXPIRE_SECONDS;
|
|
return EXPIRE_SECONDS;
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+}
|