feat(密钥): 用户 API 密钥服务端化——V115 按账号绑定存储 + 后台密钥管理页 + 桌面端全站拦截与配置引导

- 新增 usersecret 模块:外观专利/货源查询密钥从本地 localStorage 迁移至 biz_user_api_secret(AES 加密、按 uid 绑定)
- 后台「密钥管理」页:脱敏展示、立即检测、清空;每日 04:30 分布式锁定时巡检
- 桌面端:密钥设置面板走服务端、未配齐引导 /setup-secrets、代理余量展示
- 删除专利汇令牌全链路与密钥保留时长选择器
This commit is contained in:
2026-09-13 10:03:59 +08:00
parent d1b56918fa
commit 82a782550e
61 changed files with 4108 additions and 655 deletions
@@ -308,6 +308,16 @@ aiimage:
archive-connect-timeout-millis: ${AIIMAGE_IMAGE_VIDEO_ARCHIVE_CONNECT_TIMEOUT_MILLIS:10000}
archive-read-timeout-millis: ${AIIMAGE_IMAGE_VIDEO_ARCHIVE_READ_TIMEOUT_MILLIS:600000}
archive-max-attempts: ${AIIMAGE_IMAGE_VIDEO_ARCHIVE_MAX_ATTEMPTS:3}
user-secret:
check-enabled: ${AIIMAGE_USER_SECRET_CHECK_ENABLED:true}
check-cron: ${AIIMAGE_USER_SECRET_CHECK_CRON:0 30 4 * * *}
check-max-rows: ${AIIMAGE_USER_SECRET_CHECK_MAX_ROWS:500}
check-budget-minutes: ${AIIMAGE_USER_SECRET_CHECK_BUDGET_MINUTES:20}
# 检测出口代理提取链接:留空=直连;配置后检测优先经代理、失败回退直连
check-proxy-extract-url: ${AIIMAGE_USER_SECRET_CHECK_PROXY_EXTRACT_URL:}
jikip-balance-url: ${AIIMAGE_USER_SECRET_JIKIP_BALANCE_URL:https://api.jikip.com/find-balance}
jikip-plan-id: ${AIIMAGE_USER_SECRET_JIKIP_PLAN_ID:}
jikip-user-id: ${AIIMAGE_USER_SECRET_JIKIP_USER_ID:}
security:
shop-credential-key: ${AIIMAGE_SHOP_CREDENTIAL_KEY:change-me-shop-credential-key}
internal-token: ${AIIMAGE_INTERNAL_TOKEN:}
@@ -0,0 +1,31 @@
-- V115: 用户 API 密钥服务端化(外观专利密钥 / 货源查询密钥)
-- 密钥从客户端本地存储迁移到服务端,按登录用户绑定、加密存储;
-- 同时记录连通性检测状态,供后台「密钥管理」页展示与每日定时巡检更新。
CREATE TABLE IF NOT EXISTS `biz_user_api_secret` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL COMMENT '用户IDusers.id',
`module_key` VARCHAR(64) NOT NULL COMMENT '密钥模块:appearance-patent/similar-asin',
`secret_value` VARCHAR(2048) NOT NULL COMMENT '密钥密文(AES 加密)',
`check_status` VARCHAR(16) NOT NULL DEFAULT 'unknown' COMMENT '连通性状态:unknown/passed/failed/error',
`check_code` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '检测结果码:ok/invalid_key/forbidden/bad_request/rate_limited/server_error/network_error/provider_error',
`check_message` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '检测结果说明',
`check_latency_ms` INT NULL COMMENT '检测耗时(毫秒)',
`checked_at` DATETIME NULL COMMENT '最近检测时间',
`source` VARCHAR(16) NOT NULL DEFAULT 'client' COMMENT '写入来源:client/admin/migrated',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_module` (`user_id`, `module_key`),
KEY `idx_check_status` (`check_status`),
KEY `idx_checked_at` (`checked_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户 API 密钥(服务端存储,按用户绑定)';
-- 后台菜单:密钥管理(挂在「账号与权限」分组下;幂等,仅当 column_key 不存在时插入)
INSERT INTO columns (name, column_key, menu_type, route_path, sort_order, parent_id)
SELECT '密钥管理', 'admin_user_secrets', 'admin', 'account/user-secrets', 41, parent.id
FROM columns parent
WHERE parent.column_key = 'admin_group_account'
AND NOT EXISTS (
SELECT 1 FROM columns WHERE column_key = 'admin_user_secrets'
);