feat(auth,gateway,user): X-API-Key 真接线 + key 一律超管 + owner 档案真落盘(裁决 15.4.2/15.4.3/10.4.5/08.4.2)
- 15.4.2:管理 API 与 Bearer 共用同一 Authorize 路径,X-API-Key 命中签发表即过门;未知/已吊销/空值 401 且不回落 Bearer(fail-closed) - 15.4.3:key 表去掉角色维度,任一有效 key 鉴权后即 owner;签发接口取消 role 分级(不再读请求体) - 10.4.5:新增 GET/PUT /api/v1/admin/owner-profile(owner-only,PUT 带审计 owner.profile.update),0600 原子落盘 + 活档案热替换;前端主人档案改接真实 API,读不到即禁用保存,删掉硬编码默认档案 - 08.4.2:persona 的 identity.systemPrompt 必填,缺失/空白 400 显式报错,不再派生回落
This commit is contained in:
1 parent
8c6466cb00
commit
adef36538f
13 files changed
+1223
-199
No files matched your search
@@ -22,10 +22,10 @@ func (s *Server) Handler() http.Handler {
|
||||
// 已认证角色」:它指 viewer 角色存在的那个只读监控
|
||||
// 表面(模块清单、运行时指标/trace、日志尾部
|
||||
// 与通知 feed)—— 见 registerAdminRoutes。
|
||||
anyAuth := s.auth.Authorize()
|
||||
ownerAuth := s.auth.Authorize(auth.RoleOwner)
|
||||
writeAuth := s.auth.Authorize(auth.RoleOwner, auth.RoleAdmin)
|
||||
viewerAuth := s.auth.Authorize(auth.RoleOwner, auth.RoleAdmin, auth.RoleViewer)
|
||||
anyAuth := s.authorize()
|
||||
ownerAuth := s.authorize(auth.RoleOwner)
|
||||
writeAuth := s.authorize(auth.RoleOwner, auth.RoleAdmin)
|
||||
viewerAuth := s.authorize(auth.RoleOwner, auth.RoleAdmin, auth.RoleViewer)
|
||||
|
||||
s.registerPublicRoutes(mux)
|
||||
s.registerUserRoutes(mux, anyAuth, ownerAuth, writeAuth)
|
||||
@@ -121,8 +121,7 @@ func (s *Server) registerHistoryRoutes(mux *http.ServeMux, writeAuth func(http.H
|
||||
// - ownerAuth(owner):带审计的策略写、每个获取凭据的
|
||||
// 渠道端点(login-qr/login-status)以及每一个其他变更。
|
||||
//
|
||||
// 每个写 handler 都会持久化到真实后端存储,或用明确的
|
||||
// "M10 / not-wired" 错误诚实作答,而不是编造成功。
|
||||
// 管理写路由表见 registerAdminWriteRoutes。
|
||||
func (s *Server) registerAdminRoutes(
|
||||
mux *http.ServeMux,
|
||||
ownerAuth func(http.Handler) http.Handler,
|
||||
@@ -163,9 +162,19 @@ func (s *Server) registerAdminRoutes(
|
||||
mux.Handle("POST /api/v1/admin/rag/query", writeAuth(http.HandlerFunc(s.adminSearchRag)))
|
||||
mux.Handle("POST /api/v1/admin/plugins/policy", ownerAuth(http.HandlerFunc(s.adminSetPolicy)))
|
||||
|
||||
// 管理写:仅 owner,带审计。
|
||||
s.registerAdminWriteRoutes(mux, ownerAuth)
|
||||
}
|
||||
|
||||
// registerAdminWriteRoutes 挂载管理写路由:仅 owner,带审计。每个 handler 都会
|
||||
// 持久化到真实后端存储,或用明确的 "M10 / not-wired" 错误诚实作答,而不是编造成功。
|
||||
func (s *Server) registerAdminWriteRoutes(mux *http.ServeMux, ownerAuth func(http.Handler) http.Handler) {
|
||||
mux.Handle("POST /api/v1/admin/personas", ownerAuth(http.HandlerFunc(s.adminCreatePersona)))
|
||||
mux.Handle("PUT /api/v1/admin/personas/{id}", ownerAuth(http.HandlerFunc(s.adminUpdatePersona)))
|
||||
// 主人档案(裁决 10.4.5):白名单 + 显示名/关系备注的真实读写。
|
||||
// **仅 owner** —— 这份档案决定谁能进 owner 车道(design/11 §0 的身份红线),
|
||||
// 因此既不给 viewer 读、也不给 admin 写。
|
||||
mux.Handle("GET /api/v1/admin/owner-profile", ownerAuth(http.HandlerFunc(s.adminGetOwnerProfile)))
|
||||
mux.Handle("PUT /api/v1/admin/owner-profile", ownerAuth(http.HandlerFunc(s.adminPutOwnerProfile)))
|
||||
mux.Handle("POST /api/v1/admin/users", ownerAuth(http.HandlerFunc(s.adminCreateUser)))
|
||||
mux.Handle("POST /api/v1/admin/users/apikey", ownerAuth(http.HandlerFunc(s.adminIssueApiKey)))
|
||||
mux.Handle("DELETE /api/v1/admin/users/apikey/{id}", ownerAuth(http.HandlerFunc(s.adminRevokeApiKey)))
|
||||
@@ -212,6 +221,32 @@ func (s *Server) mountWebhooks(mux *http.ServeMux) {
|
||||
}
|
||||
}
|
||||
|
||||
// authorize 返回要求给定角色的凭据门。它由 Bearer JWT 门加上 `X-API-Key`
|
||||
// 分支组成(裁决 15.4.2):key 表已注入时两种凭据都收,否则只认 Bearer。
|
||||
// 按裁决 15.4.3,任何有效 key 一律 owner 级(owner 满足一切角色要求),
|
||||
// 未知/已吊销 key 一律 401 且不回落 Bearer(fail-closed,见 auth.WithAPIKey)。
|
||||
func (s *Server) authorize(required ...auth.Role) func(http.Handler) http.Handler {
|
||||
bearer := s.auth.Authorize(required...)
|
||||
keys := s.apiKeyTable()
|
||||
if keys == nil {
|
||||
return bearer
|
||||
}
|
||||
return auth.WithAPIKey(keys, bearer, s.log, required...)
|
||||
}
|
||||
|
||||
// apiKeyTable 返回注入的 API key 表;未注入(或注入的实现不是 key 表)时为
|
||||
// nil,此时鉴权只认 Bearer —— 「表不在」等同空表,绝不因此放行任何 key。
|
||||
func (s *Server) apiKeyTable() auth.KeyTable {
|
||||
if s.users == nil {
|
||||
return nil
|
||||
}
|
||||
table, ok := s.users.(auth.KeyTable)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
// withMiddleware 把已路由的 handler 包进外层,最外层在前:
|
||||
// 上传能力 URL 防护、SPA 回退(当配置了前端时)、
|
||||
// panic recover、CORS 与请求日志。
|
||||
|
||||
Reference in new issue
Block a user