This commit is contained in:
+8
@@ -2,6 +2,7 @@ package com.nanri.aiimage.common.security;
|
||||
|
||||
import com.nanri.aiimage.common.exception.BusinessException;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -12,8 +13,11 @@ import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ShopCredentialCryptoService {
|
||||
|
||||
private static final String INSECURE_DEFAULT_KEY = "change-me-shop-credential-key";
|
||||
|
||||
@Value("${aiimage.security.shop-credential-key:change-me-shop-credential-key}")
|
||||
private String rawKey;
|
||||
|
||||
@@ -22,6 +26,10 @@ public class ShopCredentialCryptoService {
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
if (rawKey == null || rawKey.isBlank() || INSECURE_DEFAULT_KEY.equals(rawKey.trim())) {
|
||||
log.warn("[security] AIIMAGE_SHOP_CREDENTIAL_KEY 未配置或仍为默认值,店铺凭据加密强度不足,"
|
||||
+ "请通过环境变量 AIIMAGE_SHOP_CREDENTIAL_KEY 配置固定密钥");
|
||||
}
|
||||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
|
||||
byte[] full = sha256.digest(rawKey.getBytes(StandardCharsets.UTF_8));
|
||||
byte[] key16 = new byte[16];
|
||||
|
||||
@@ -27,9 +27,15 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOriginPatterns(List.of("*"));
|
||||
// 限制为可信域名,支持本地开发和生产环境
|
||||
configuration.setAllowedOriginPatterns(List.of(
|
||||
"http://localhost:*",
|
||||
"http://127.0.0.1:*",
|
||||
"https://*.aishufu.top",
|
||||
"http://*.aishufu.top"
|
||||
));
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type", "X-Requested-With", "X-Device-Id", "X-Internal-Token"));
|
||||
configuration.setExposedHeaders(List.of("Content-Disposition"));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
@@ -20,16 +21,42 @@ import java.util.Date;
|
||||
@Slf4j
|
||||
public class JwtService {
|
||||
|
||||
private static final String INSECURE_DEFAULT_SECRET = "please-change-this-secret-please-rotate-at-least-32-bytes";
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
private final AuthProperties props;
|
||||
|
||||
private volatile SecretKey cachedKey;
|
||||
|
||||
private SecretKey signingKey() {
|
||||
byte[] keyBytes = props.getJwtSecret().getBytes(StandardCharsets.UTF_8);
|
||||
if (keyBytes.length < 32) {
|
||||
byte[] padded = new byte[32];
|
||||
System.arraycopy(keyBytes, 0, padded, 0, keyBytes.length);
|
||||
keyBytes = padded;
|
||||
SecretKey key = cachedKey;
|
||||
if (key == null) {
|
||||
synchronized (this) {
|
||||
key = cachedKey;
|
||||
if (key == null) {
|
||||
String configured = props.getJwtSecret();
|
||||
boolean insecure = configured == null || configured.isBlank()
|
||||
|| INSECURE_DEFAULT_SECRET.equals(configured.trim());
|
||||
byte[] keyBytes;
|
||||
if (insecure) {
|
||||
keyBytes = new byte[32];
|
||||
SECURE_RANDOM.nextBytes(keyBytes);
|
||||
log.warn("[auth] AIIMAGE_JWT_SECRET 未配置或仍为默认值,已自动生成随机密钥;"
|
||||
+ "服务重启后已签发的 token 将失效,请通过环境变量 AIIMAGE_JWT_SECRET 配置固定密钥");
|
||||
} else {
|
||||
keyBytes = configured.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
if (keyBytes.length < 32) {
|
||||
byte[] padded = new byte[32];
|
||||
System.arraycopy(keyBytes, 0, padded, 0, keyBytes.length);
|
||||
keyBytes = padded;
|
||||
}
|
||||
key = Keys.hmacShaKeyFor(keyBytes);
|
||||
cachedKey = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
return key;
|
||||
}
|
||||
|
||||
public String issue(Long userId, String username, String deviceId) {
|
||||
|
||||
Reference in New Issue
Block a user