Compare commits

..

2 Commits

Author SHA1 Message Date
huangzd1997 7b81b7aa01 品牌去重默认勾选列调整为 ASIN/国家/价格/SKU ID/品牌
Build Backend JAR / build (push) Has been cancelled
2026-08-25 22:00:33 +08:00
huangzd1997 427a8cb79f 修复:JWT 密钥未配置时使用内置默认密钥,与桌面客户端保持一致 2026-08-25 22:00:30 +08:00
2 changed files with 8 additions and 10 deletions
@@ -11,7 +11,6 @@ import org.springframework.stereotype.Service;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Date; import java.util.Date;
@@ -22,7 +21,6 @@ import java.util.Date;
public class JwtService { public class JwtService {
private static final String INSECURE_DEFAULT_SECRET = "please-change-this-secret-please-rotate-at-least-32-bytes"; 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 final AuthProperties props;
@@ -35,14 +33,13 @@ public class JwtService {
key = cachedKey; key = cachedKey;
if (key == null) { if (key == null) {
String configured = props.getJwtSecret(); String configured = props.getJwtSecret();
boolean insecure = configured == null || configured.isBlank()
|| INSECURE_DEFAULT_SECRET.equals(configured.trim());
byte[] keyBytes; byte[] keyBytes;
if (insecure) { if (configured == null || configured.isBlank()) {
keyBytes = new byte[32]; // 已分发到用户机器的桌面客户端内置同一个默认密钥,服务端必须保持一致,
SECURE_RANDOM.nextBytes(keyBytes); // 不能随机生成,否则所有旧客户端 /api/auth/sync 验签失败导致无法登录。
log.warn("[auth] AIIMAGE_JWT_SECRET 未配置或仍为默认值,已自动生成随机密钥;" keyBytes = INSECURE_DEFAULT_SECRET.getBytes(StandardCharsets.UTF_8);
+ "服务重启后已签发的 token 将失效,请通过环境变量 AIIMAGE_JWT_SECRET 配置固定密钥"); log.warn("[auth] AIIMAGE_JWT_SECRET 配置,使用内置默认密钥"
+ "生产环境请通过环境变量 AIIMAGE_JWT_SECRET 配置固定密钥(需与桌面客户端一致)");
} else { } else {
keyBytes = configured.getBytes(StandardCharsets.UTF_8); keyBytes = configured.getBytes(StandardCharsets.UTF_8);
} }
@@ -201,13 +201,14 @@ async function loadCleanHeaders(fileKey: string) {
} }
const preferredHeaders = ['id', 'ASIN', '国家', '价格', '卖家名称', '品牌', 'SKU ID', '发货类型'] const preferredHeaders = ['id', 'ASIN', '国家', '价格', '卖家名称', '品牌', 'SKU ID', '发货类型']
const defaultSelectedHeaders = ['ASIN', '国家', '价格', 'SKU ID', '品牌']
const orderedHeaders = [ const orderedHeaders = [
...preferredHeaders.filter((header) => result.headers?.includes(header)), ...preferredHeaders.filter((header) => result.headers?.includes(header)),
...(result.headers || []).filter((header) => !preferredHeaders.includes(header)), ...(result.headers || []).filter((header) => !preferredHeaders.includes(header)),
] ]
cleanAvailableColumns.value = orderedHeaders cleanAvailableColumns.value = orderedHeaders
cleanSelectedColumns.value = preferredHeaders.filter((header) => orderedHeaders.includes(header)) cleanSelectedColumns.value = defaultSelectedHeaders.filter((header) => orderedHeaders.includes(header))
} }
async function handleSelectedPaths(paths: string[], successMessage: string) { async function handleSelectedPaths(paths: string[], successMessage: string) {