feat(backend): 会话安全加固 + 授权实时 phase + 首次使用自动试用

会话安全(jti 轮换 / 重用检测 / 改密吊销 / 禁用即时下线 / 清理 / 失败登录落库):
- refresh token 轮换 jti + token-family 重用检测,旧 token 重放即吊销整条会话
- 改密码、停用用户即时吊销其全部活跃会话(revoked_by 审计)
- 中间件 session JOIN user 校验,禁用/删除用户带 token 请求返回 401 USER_DISABLED
- 新增 login_attempts 失败登录落库 + 会话保留期清理 goroutine

授权实时 phase + 心跳回带:
- LicenseGuard 改为按当前 DB 实时计算 phase(30s 每店缓存),续费/过期/被改 ~30s 内对写操作生效,无需重登
- /auth/ping 回带授权概况(ShopInfoView,与 /license/info 同构),客户端一次心跳即刷新横幅/门禁

首次使用自动试用 + code-review 修复:
- 门店首次登录/续期无有效授权时自动签发 30 天 trial(快路径无锁 Count,仅首用走 FOR UPDATE 事务)
- ShopInfo 区分「确无授权」与瞬时 DB 错误,避免误降级
- trial 签发后改为在事务提交后再失效 phase 缓存(修复早于提交的竞态)
- 存量无 sid token 续期纳入显式上限,legacy 会话不再游离于并发配额之外

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-19 07:34:04 +08:00
parent 2d84bda99a
commit e41085a878
23 changed files with 1248 additions and 74 deletions
+5
View File
@@ -12,6 +12,7 @@ import (
"github.com/wangjia/jiu/backend/config"
"github.com/wangjia/jiu/backend/internal/model"
"github.com/wangjia/jiu/backend/internal/router"
"github.com/wangjia/jiu/backend/internal/service"
)
func main() {
@@ -37,6 +38,9 @@ func main() {
// 自动迁移(GORM AutoMigrate 只增不删,生产安全)
autoMigrate(db)
// 启动会话/失败登录保留期清理任务(后台 goroutine)
service.StartSessionCleanup(db, config.C.Session.RetentionDays)
// 启动 Gin
gin.SetMode(config.C.Server.Mode)
r := gin.New()
@@ -98,6 +102,7 @@ func autoMigrate(db *gorm.DB) {
&model.License{},
&model.LicenseDevice{},
&model.UserSession{},
&model.LoginAttempt{},
&model.ProductCategory{},
&model.Product{},
&model.Warehouse{},