fix(auth): API Key 落盘(修「每次重启 key 全失效」)
- 缺陷:internal/auth/apikey.go 的 key 表是纯内存 map(注释自认 production should persist)⇒ 一次 restart 后所有 key 一律 401;实测挡住了大附件真机 e2e,也与「key 用于生产救火」的长凭据语义矛盾。 - 迁移 0016_api_keys:表 api_keys(id/name/key_hash/created_at/last_used_at/revoked_at)+ 唯一索引 idx_api_keys_key_hash;**只存 SHA-256 hash,无明文入口**。 - 纪律:Generate 先落库后改内存(失败 ⇒ 内存不变 + 返回错误);AttachKeyStore 启动时把库中未吊销 hash 载入内存(Load 失败仍接上 store ⇒ Generate 会响亮报错,而不是静默退回「不落盘」);Revoke/RevokeAll/RevokeByMask 先落库再移出内存(落库失败 ⇒ WARN + 内存不变,fail-closed:绝不让被吊销的 key 重启后复活)。 - 内存表也改为存 hash(不再存明文)⇒ 面板 id/掩码由 hash 派生:不再泄露明文首尾、且跨重启稳定(重启前记下的 id 重启后仍可吊销)。 - 契约零变化:HTTP 请求/响应形状、网关代码、既有内存用例断言全部未动(网关构造注入点只在组合根 wireAPIKeys)。 - 主会话独立验收:隔离 worktree(K1 的 7 文件)build/vet 绿、全树 59 包 0 FAIL、key 用例 24 PASS、双平台交叉编译绿;变异独立复现(跳过落库 ⇒ 重启存活用例红)。 - 取舍与遗留:吊销落库失败在 HTTP 层仍表现为 404/revoked:0(签名零改动的代价,日志可辨);last_used_at 列已建但恒 NULL(避免把读路径变写路径);旧内存 key 已被此前重启消灭,需重签一次后即长期有效。
This commit is contained in:
1 parent
c3339a5d07
commit
79b1ec36aa
7 files changed
+917
-57
No files matched your search
@@ -24,7 +24,7 @@ type capacityEmitter interface {
|
||||
// 返回真实数据。
|
||||
func (a *app) wireFrontend() error {
|
||||
jwt := auth.New(a.cfg.Auth)
|
||||
apiKeys := auth.NewAPIKey(a.cfg.Auth)
|
||||
apiKeys := a.wireAPIKeys()
|
||||
ragStore := knowledge.New(knowledge.Deps{
|
||||
Projects: a.projStore,
|
||||
Retriever: a.retriever,
|
||||
@@ -116,6 +116,30 @@ func (a *app) wireFrontend() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// wireAPIKeys 构造 API key 管理器,并把落盘载体接到它上面(K1:修「每次重启 key
|
||||
// 全失效」——此前 key 表只在内存里,主人刚签的 key 被一次重启全部打掉,签发端点
|
||||
// 长凭据的语义与「重启即作废」自相矛盾)。
|
||||
//
|
||||
// 降级口径与上面的 refresh store 一致:构造或载入失败**不阻断启动**,key 仍可签发
|
||||
// 与校验,只是不跨重启存活;后果写进日志,不静默。注意 AttachKeyStore 在 Load 失败
|
||||
// 时仍会把 store 接上(见其注释)——那样之后的签发会响亮地失败,而不是又一次
|
||||
// 「面板报成功、重启全 401」。
|
||||
func (a *app) wireAPIKeys() *auth.APIKey {
|
||||
keys := auth.NewAPIKey(a.cfg.Auth)
|
||||
if a.db == nil {
|
||||
return keys
|
||||
}
|
||||
store, err := auth.NewSQLiteKeyStore(a.db, a.log)
|
||||
if err != nil {
|
||||
a.log.Warn("api key store unavailable, issued keys will not survive restart", "error", err)
|
||||
return keys
|
||||
}
|
||||
if err := keys.AttachKeyStore(context.Background(), store); err != nil {
|
||||
a.log.Warn("api key store load failed, keys issued earlier may be rejected", "error", err)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// vectorState 把「PG 增强到底有没有生效」的**运行时真相**报给网关,供管理侧
|
||||
// 「存储状态」只读端点作答(design/03 §3;面板首页的存储卡)。
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user