feat(auth): refresh token revoked 行复用信号(日志+指标) - #2188
Merged
Conversation
…_total 计数器) #2154 F2 低风险步①:只加信号,不做级联吊销(级联是决策项)。 - service/auth RefreshToken:Revoked 行命中时 slog.Warn(user_id/device_type 维度,不记录 token 本体或 hash)+ refresh_token_reuse_total 计数器, 响应语义不变(仍 AuthRefreshInvalid),轮换逻辑不动。 - metrics:新 plain Counter 按既有 #1441 nil-guard 模式注册(G9 旁)。 - 测试:登出后复用 → 拒绝 + 计数器恰 +1 + 无级联(sqlmock 期望耗尽证明 该用户其它令牌未被吊销);过期未撤销路径不计入(信号特异性)。 - 已知限制(不改):轮换走 UpsertRefreshToken ON CONFLICT 覆盖旧 hash, 轮换后旧 token 复用在 DB 侧结构性不可检测;本信号只覆盖登出撤销行。 Co-authored-by: Cursor <cursor@vectorcontrol.tech>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Service.RefreshToken命中 已撤销(Revoked==true) 的 refresh token 行时,从静默拒绝升级为「拒绝 + 可观测信号」:slog.Warn(仅user_id/device_type维度,不记录 token 本体或 hash)+ 新 plain Counterrefresh_token_reuse_total(按 #1441 nil-guard 既有模式在metrics.Register()注册,紧邻 G9RefreshBlacklistCheckErrors)。响应错误码不变(仍AuthRefreshInvalid),轮换逻辑不动。已撤销行被再次出示是 refresh 链路上唯一可在 DB 侧检测的复用信号(如登出后被窃令牌重放)。取证(复核属实)
hub-server/internal/repository/refresh_token.goUpsertRefreshToken:ON CONFLICT (user_id, device_type, device_id) DO UPDATE token_hash/expires_at/revoked覆盖旧 hash → 轮换后旧 token 复用在 DB 侧结构性不可检测(本轮不改,见「已知限制」)。hub-server/internal/service/auth/service.go:55-57(改前):查无 → 静默AuthRefreshInvalid;查到但Revoked==true或过期 → 同一if静默拒绝,无日志区分、无指标——复用与正常过期失败在运维面完全不可分辨。internal/service/auth/已有newMockDB(sqlmock)+ miniredis +testutil.ToFloat64计数器断言先例(refresh_fail_closed_redis_test.goTestRefreshBlacklistCheckErrorsCounter),新测试完全仿写。Scope 边界
refresh_tokens表、不动 upsert 语义。AuthRefreshInvalid。service/auth与handler/auth.go零 audit 引用),故只做 warn+指标。Revoked || expired合并分支:过期(未撤销)路径保持静默、不计入复用计数器(有测试锁定特异性)。测试证据
新增
hub-server/internal/service/auth/refresh_reuse_signal_test.go(2 用例):TestRefreshToken_RevokedReuseSignal:登出(Logout→ revoke UPDATE)后复用同一令牌 →AuthRefreshInvalid拒绝 +refresh_token_reuse_total恰 +1 + 无级联(sqlmock 期望在复用查询后耗尽,任何针对该用户其它令牌行的吊销 UPDATE 会以 unexpected Exec 使ExpectationsWereMet失败)。TestRefreshToken_ExpiredNoReuseSignal:过期未撤销 → 同错误码但计数器 +0(信号特异性)。metrics_test.go按既有惯例补RefreshTokenReuseTotalnil 检查 +refresh_token_reuse_total注册断言。门禁(本地全绿):
go vet ./...(hub-server)、go test ./internal/service/auth/ ./internal/repository/ ./internal/handler/ ./internal/metrics/、make test(test-edge + test-hub 全量)、verify-doc-ssot.py、git diff --check、verify-ci-gates.py、verify-openapi-contract.py、verify-migration-idempotency.py、verify-test-sleep-ratchet.py、verify-conventions.py、verify-hub-pure-packages.py、verify-hub-layering.py、verify-i18n-deadkeys.py、verify-commit-messages.sh origin/master HEAD。注:本地
verify-hub-lint-ratchet.py报 gosec G101 findings,在未改动的 master(a91d071,主检出)上同样复现且条数更多(本机 gosec/revive 版本漂移,finding 集不稳定,与本 diff 无关——本 diff 未触碰任何被报文件),以 CI 固定工具链为准。已知限制(不改,登记在案)
轮换走
UpsertRefreshTokenON CONFLICT DO UPDATE token_hash:同一设备再登录即覆盖旧 hash,轮换后旧 token 的复用在 DB 侧结构性不可检测(仅轮换时写入的 Redis 黑名单在 TTL 窗口内兜底)。本信号只覆盖「登出/显式撤销后行仍存在且被重放」这一可检测子集。彻底修复需 schema 变更(保留旧 hash 或独立复用事件表),属决策项,不在本轮。后续决策项
关联:#2154 F2 低风险步①。