feat(认证/通知): 单设备登录互踢 + 站内通知铃铛系统
- 单设备登录:登录成功即 last-login-wins 绑定 users.machine;非超管旧 token 在下一次受保护请求抛 4011 下线,超管豁免;仅认 token 内签名 deviceId,不用请求头。 前端两端接入踢下线跳转(?kicked=1 提示),V118 清空历史 machine - 站内通知:新增 notification 模块(任务失败扫描 / 密钥欠费 / 下游服务探测三类来源), 前后台铃铛组件 + 轮询;后台列表按主管数据范围(UserDataScopeSupport)过滤;V116 建表 均已于 2026-09-13 部署上线,此次补提交源码(此前仅存在于已部署 JAR/构建产物中)
This commit is contained in:
@@ -318,6 +318,22 @@ aiimage:
|
||||
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:}
|
||||
# 巡检发现欠费/密钥失效时是否推送站内通知(铃铛)
|
||||
notify-enabled: ${AIIMAGE_USER_SECRET_NOTIFY_ENABLED:true}
|
||||
# 站内通知(铃铛):任务失败扫描 + 下游服务健康探测
|
||||
notification:
|
||||
scan-enabled: ${AIIMAGE_NOTIFICATION_SCAN_ENABLED:true}
|
||||
scan-interval-ms: ${AIIMAGE_NOTIFICATION_SCAN_INTERVAL_MS:300000}
|
||||
scan-initial-delay-ms: ${AIIMAGE_NOTIFICATION_SCAN_INITIAL_DELAY_MS:120000}
|
||||
task-scan-enabled: ${AIIMAGE_NOTIFICATION_TASK_SCAN_ENABLED:true}
|
||||
task-failed-window-minutes: ${AIIMAGE_NOTIFICATION_TASK_FAILED_WINDOW_MINUTES:60}
|
||||
task-scan-max-rows: ${AIIMAGE_NOTIFICATION_TASK_SCAN_MAX_ROWS:1000}
|
||||
service-probe-enabled: ${AIIMAGE_NOTIFICATION_SERVICE_PROBE_ENABLED:true}
|
||||
# 探测地址留空=跳过该项;部署时按主机拓扑配置(15126 品牌检测 / 18960 跟价任务 API)
|
||||
brand-service-url: ${AIIMAGE_NOTIFICATION_BRAND_SERVICE_URL:}
|
||||
price-track-api-url: ${AIIMAGE_NOTIFICATION_PRICE_TRACK_API_URL:}
|
||||
jikip-probe-enabled: ${AIIMAGE_NOTIFICATION_JIKIP_PROBE_ENABLED:true}
|
||||
read-retention-days: ${AIIMAGE_NOTIFICATION_READ_RETENTION_DAYS:90}
|
||||
security:
|
||||
shop-credential-key: ${AIIMAGE_SHOP_CREDENTIAL_KEY:change-me-shop-credential-key}
|
||||
internal-token: ${AIIMAGE_INTERNAL_TOKEN:}
|
||||
@@ -328,6 +344,7 @@ aiimage:
|
||||
cookie-name: ${AIIMAGE_AUTH_COOKIE_NAME:aiimage_token}
|
||||
cookie-secure: ${AIIMAGE_AUTH_COOKIE_SECURE:false}
|
||||
cookie-same-site: ${AIIMAGE_AUTH_COOKIE_SAME_SITE:Lax}
|
||||
single-device-enabled: ${AIIMAGE_AUTH_SINGLE_DEVICE_ENABLED:true}
|
||||
ziniao:
|
||||
enabled: ${AIIMAGE_ZINIAO_ENABLED:false}
|
||||
base-url: ${AIIMAGE_ZINIAO_BASE_URL:https://sbappstoreapi.ziniao.com/openapi-router}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- V116: 站内通知(铃铛)
|
||||
-- 桌面端用户与后台管理员共用的通知表,按 audience 区分接收端;
|
||||
-- 通知来源:密钥巡检(欠费/失效)、任务失败扫描、下游服务健康探测。
|
||||
-- dedupe_key 自带时间粒度(当天/当小时/任务号),插入前精确查重实现去重。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `biz_user_notification` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT NOT NULL COMMENT '接收者ID(users.id)',
|
||||
`audience` VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '接收端:user=桌面端/admin=后台',
|
||||
`scene` VARCHAR(32) NOT NULL DEFAULT 'system' COMMENT '场景:secret_balance/secret_invalid/task_failed/service_down/system',
|
||||
`level` VARCHAR(16) NOT NULL DEFAULT 'warning' COMMENT '级别:info/warning/error',
|
||||
`title` VARCHAR(128) NOT NULL COMMENT '通知标题',
|
||||
`content` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '通知内容',
|
||||
`dedupe_key` VARCHAR(160) NOT NULL DEFAULT '' COMMENT '去重键(自带时间粒度,插入前精确查重)',
|
||||
`read_at` DATETIME NULL COMMENT '已读时间(NULL=未读)',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_audience_read` (`user_id`, `audience`, `read_at`, `id`),
|
||||
KEY `idx_dedupe` (`dedupe_key`),
|
||||
KEY `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内通知(桌面端用户 + 后台管理员)';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- V118: 清空 users.machine,为单设备登录(互踢)做干净起点
|
||||
-- 背景:users.machine 是早期「设备绑定」遗留列,绑定逻辑停用后一直没维护,
|
||||
-- 存量值与用户当前设备普遍不一致。单设备登录上线后校验 machine 与
|
||||
-- token 内签名 deviceId 是否一致,若不清空,历史残留会导致用户部署后
|
||||
-- 立刻被判「已在其他设备登录」而下线(提示还是错的)。
|
||||
-- 清空后:已登录用户不受影响,每人下一次登录时写入当前设备,自然进入新规则。
|
||||
-- 幂等:只清非空值,重复执行无副作用。
|
||||
|
||||
UPDATE `users` SET `machine` = NULL WHERE `machine` IS NOT NULL;
|
||||
Reference in New Issue
Block a user