数据库 Token 认证
部署前执行同目录 user_tokens.sql,在现有业务库 wxxd 中建立唯一的新表;应用不自动修改表结构。
启动:dotnet run --project Store.API/Store.Api.csproj。宿主使用 AddStoreHubTokenAuth,管道继续使用 UseAuthentication / UseAuthorization。
登录接口仍返回 tokenType、token、expiresInMinutes,可选传入 deviceId、deviceName(各最多 100 字符)。
客户端按 Authorization: Bearer {token} 发送;Token 是 32 字节安全随机数的标准 Base64(44 字符),数据库仅存 SHA256 十六进制哈希。
expiresInMinutes 表示签发时的闲置有效期;服务端使用滑动过期,客户端无需刷新令牌。
TokenAuth 默认配置:IdleDays=7、AbsoluteMaxDays=30、RenewIntervalMinutes=10、CacheSeconds=30、MaxDevicesPerUser=0。
全部时间按 UTC 保存(DATETIME 不带时区);每次使用达到续期间隔才条件更新到期时间,绝不超过创建时间加绝对期限。
内存缓存使用固定到期时间,命中不会延长缓存寿命。缓存期间仍检查闲置及绝对期限。
每次登录创建新记录;相同非空 deviceId 会替换其旧记录。未提供 deviceId 的登录按独立设备计数。
设备数为 0 时无限制,为 1 时单点登录,为 N 时保留最多 N 个有效会话,超限撤销最早的会话。
签发在事务中锁定现有用户行,使多实例的并发登录也遵守数量限制。MySQL 业务用户表需使用 InnoDB。
退出当前会话、修改密码后的全部会话撤销以及设备替换统一更新 Revoked 并清除当前实例缓存。
宿主注册 Hangfire 任务 token-cleanup,每天北京时间 03:00(UTC 19:00)删除已撤销、闲置到期或达到绝对期限的记录;可在 /hangfire 查看执行结果。任务执行需要宿主运行。
多实例下其他实例最多延迟 CacheSeconds 秒获知撤销;要求每次查库时设置 CacheSeconds=0。
用户信息在缓存未命中时从实际 wxxd.user 表读取 id/user_name/nick_name;当前用户表没有 IsEnabled 或 Role 字段,因此未假设这些字段或新增角色策略。
数据库故障向上抛出,由宿主处理错误,认证不会在数据库不可用时绕过校验。
切换后旧 JWT 失效,用户需要重新登录。旧 auth_login_session 表不再使用,保留供人工归档。
开发固定凭据配置位于 TokenAuth:DevelopmentToken(Enabled、Token、UserName):基础配置禁用,appsettings.Development.json 开启,仅 Development 环境生效。
使用相同的 Bearer 请求头即可测试;固定凭据不查询数据库、不创建会话、不参与滑动过期和退出吊销。关闭 Enabled 或修改 Token 可使其失效。
保留 AddStoreHubJwt 名称作为注册入口的兼容别名;JwtClaimTypes 仅保留现有声明字段名称。
校验:dotnet test Tests/Store.Security.Tests/Store.Security.Tests.csproj,使用独立 SQLite 临时库,不连接业务 MySQL。
测试涵盖重启持久化、滑动/绝对过期、设备限制、缓存撤销与开发凭据的环境限制;MySQL 行锁行为仍需部署环境验证。