主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批: 已推库 16 个文件 + 本批剩余文件)。 校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0); 全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
50 lines
1.8 KiB
Go
50 lines
1.8 KiB
Go
package gateway
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/auth"
|
|
)
|
|
|
|
// auditClaims 记录一次管理写操作,调用方身份从请求上下文读取
|
|
// (由 auth.Authorize 填充)。它是管理操作所需的
|
|
// 谁/什么/何时/结果审计链;「主代理代审」这一面向用户的提示是
|
|
// 前端的职责,不是网关的。
|
|
func (s *Server) auditClaims(r *http.Request, what, result string) {
|
|
who := "anonymous"
|
|
if claims, ok := auth.ClaimsFromContext(r.Context()); ok {
|
|
who = claims.Sub + ":" + string(claims.Role)
|
|
}
|
|
s.audit(r.Context(), who, what, result)
|
|
}
|
|
|
|
// AuditEvent 记录一次带显式调用方身份的外部(非 HTTP)审计事件,
|
|
// 使请求路径之外的程序化写入方(例如渠道 bridge 的
|
|
// 黑名单拒绝钩子,design/16 §4.6 §6)能追加到同一
|
|
// 谁/什么/何时/结果链。who 是自由形式的 actor 标签("channel" 或
|
|
// "bridge:telegram");what 是操作,result 是其结果。它对
|
|
// 并发使用安全。
|
|
func (s *Server) AuditEvent(who, what, result string) {
|
|
s.audit(context.Background(), who, what, result)
|
|
}
|
|
|
|
// audit 在网关 logger 上发出一条结构化审计记录,并把它持久化到
|
|
// 已配置的 AuditStore(未注入时回退到内存存储)。
|
|
// 持久化失败会记日志,但绝不阻塞管理写,因此
|
|
// 坏掉的审计存储无法拖垮审计链的首要职责。
|
|
func (s *Server) audit(ctx context.Context, who, what, result string) {
|
|
s.log.Info("admin audit",
|
|
"who", who,
|
|
"what", what,
|
|
"when", time.Now().UTC().Format(time.RFC3339),
|
|
"result", result,
|
|
)
|
|
if s.obs != nil && s.obs.audit != nil {
|
|
if err := s.obs.audit.Append(ctx, who, what, result, time.Now()); err != nil {
|
|
s.log.Error("admin audit persist", "err", err, "what", what)
|
|
}
|
|
}
|
|
}
|