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:
@@ -45,8 +45,9 @@ type SessionConfig struct {
|
||||
LimitDesktop int `mapstructure:"limit_desktop"` // 桌面端(win/mac/linux)最大并发会话,0=禁止
|
||||
LimitMobile int `mapstructure:"limit_mobile"` // 移动端(android/ios)最大并发会话,0=禁止
|
||||
LimitWeb int `mapstructure:"limit_web"` // web 端最大并发会话,0=禁止
|
||||
MaxFailures int `mapstructure:"max_failures"` // 连续登录失败几次后锁定
|
||||
LockMinutes int `mapstructure:"lock_minutes"` // 锁定时长(分钟)
|
||||
MaxFailures int `mapstructure:"max_failures"` // 连续登录失败几次后锁定
|
||||
LockMinutes int `mapstructure:"lock_minutes"` // 锁定时长(分钟)
|
||||
RetentionDays int `mapstructure:"retention_days"` // 已撤销/过期会话与失败登录记录的保留天数,过期后台清理
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
@@ -90,6 +91,7 @@ func Load() {
|
||||
viper.SetDefault("session.limit_web", 2) // 默认不禁 web(官网挂着 Web 版 app);设 0 可禁
|
||||
viper.SetDefault("session.max_failures", 5)
|
||||
viper.SetDefault("session.lock_minutes", 15)
|
||||
viper.SetDefault("session.retention_days", 90)
|
||||
viper.SetDefault("database.max_idle_conns", 10)
|
||||
viper.SetDefault("database.max_open_conns", 100)
|
||||
viper.SetDefault("storage.upload_dir", "./uploads/images")
|
||||
|
||||
Reference in New Issue
Block a user