Files
Cyrene_v2/internal/services/gateway/audit.go
T
AskaEth 074ffc4ebf
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批:
已推库 16 个文件 + 本批剩余文件)。
校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0);
全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
2026-10-03 22:28:25 +08:00

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)
}
}
}