|
@@ -26,20 +26,33 @@ public class JwtUtil {
|
|
|
@Value("${jwt.secret:}")
|
|
@Value("${jwt.secret:}")
|
|
|
private String secret;
|
|
private String secret;
|
|
|
|
|
|
|
|
- @Value("${jwt.expiration:}")
|
|
|
|
|
- private Long expiration;
|
|
|
|
|
|
|
+ @Value("${jwt.user-expiration:3600000}")
|
|
|
|
|
+ private Long userExpiration; // 默认 1 小时
|
|
|
|
|
+ @Value("${jwt.admin-expiration:43200000}")
|
|
|
|
|
+ private Long adminExpiration; // 默认 12 小时
|
|
|
|
|
|
|
|
@Value("${jwt.refresh-expiration:}")
|
|
@Value("${jwt.refresh-expiration:}")
|
|
|
private Long refreshExpiration;
|
|
private Long refreshExpiration;
|
|
|
|
|
|
|
|
|
|
+ private static final String ROLE_ADMIN = "ADMIN";
|
|
|
|
|
+ private static final String ROLE_SUPER_ADMIN = "SUPER_ADMIN";
|
|
|
|
|
+
|
|
|
private SecretKey getSigningKey() {
|
|
private SecretKey getSigningKey() {
|
|
|
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
|
|
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private boolean isAdminRole(String role) {
|
|
|
|
|
+ return ROLE_ADMIN.equals(role) || ROLE_SUPER_ADMIN.equals(role);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 生成访问令牌(含 tokenVersion 用于单设备登录控制)
|
|
* 生成访问令牌(含 tokenVersion 用于单设备登录控制)
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 管理员 12 小时过期,普通用户 1 小时过期,共用同一密钥签名。
|
|
|
*/
|
|
*/
|
|
|
public String generateAccessToken(Long userId, String role, Long tokenVersion) {
|
|
public String generateAccessToken(Long userId, String role, Long tokenVersion) {
|
|
|
|
|
+ long expirationMs = isAdminRole(role) ? adminExpiration : userExpiration;
|
|
|
|
|
+
|
|
|
Map<String, Object> claims = new HashMap<>();
|
|
Map<String, Object> claims = new HashMap<>();
|
|
|
claims.put("userId", userId);
|
|
claims.put("userId", userId);
|
|
|
claims.put("role", role != null ? role : "USER");
|
|
claims.put("role", role != null ? role : "USER");
|
|
@@ -50,7 +63,7 @@ public class JwtUtil {
|
|
|
.claims(claims)
|
|
.claims(claims)
|
|
|
.subject(String.valueOf(userId))
|
|
.subject(String.valueOf(userId))
|
|
|
.issuedAt(new Date())
|
|
.issuedAt(new Date())
|
|
|
- .expiration(new Date(System.currentTimeMillis() + expiration))
|
|
|
|
|
|
|
+ .expiration(new Date(System.currentTimeMillis() + expirationMs))
|
|
|
.signWith(getSigningKey())
|
|
.signWith(getSigningKey())
|
|
|
.compact();
|
|
.compact();
|
|
|
}
|
|
}
|
|
@@ -145,35 +158,6 @@ public class JwtUtil {
|
|
|
return claims.get("type", String.class);
|
|
return claims.get("type", String.class);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取用户角色(兼容旧 Token,默认 USER)
|
|
|
|
|
- */
|
|
|
|
|
- public String getRole(String token) {
|
|
|
|
|
- try {
|
|
|
|
|
- Claims claims = parseToken(token);
|
|
|
|
|
- String role = claims.get("role", String.class);
|
|
|
|
|
- return role != null ? role : "USER";
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- return "USER";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取Token版本号(用于单设备登录校验)
|
|
|
|
|
- */
|
|
|
|
|
- public Long getTokenVersion(String token) {
|
|
|
|
|
- try {
|
|
|
|
|
- Claims claims = parseToken(token);
|
|
|
|
|
- Object version = claims.get("tokenVersion");
|
|
|
|
|
- if (version instanceof Number) {
|
|
|
|
|
- return ((Number) version).longValue();
|
|
|
|
|
- }
|
|
|
|
|
- return 0L;
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- return 0L;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 对 Refresh Token 取 SHA-256 哈希(存储到DB用于旋转+重用检测)
|
|
* 对 Refresh Token 取 SHA-256 哈希(存储到DB用于旋转+重用检测)
|
|
|
*/
|
|
*/
|
|
@@ -192,9 +176,10 @@ public class JwtUtil {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 获取过期时间(秒)
|
|
|
|
|
|
|
+ * 获取 access token 过期时间(秒),按角色区分
|
|
|
*/
|
|
*/
|
|
|
- public Long getExpirationInSeconds() {
|
|
|
|
|
- return expiration / 1000;
|
|
|
|
|
|
|
+ public Long getExpirationInSeconds(String role) {
|
|
|
|
|
+ long expirationMs = isAdminRole(role) ? adminExpiration : userExpiration;
|
|
|
|
|
+ return expirationMs / 1000;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|