You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -25,6 +25,18 @@ type RouterDeps struct {
|
||||
SPAHandler http.Handler
|
||||
// Logger 用于 Recover 和 Logger 中间件。为 nil 时跳过日志相关中间件。
|
||||
Logger *slog.Logger
|
||||
// Security 是安全响应头中间件配置(cfg-gated;Enabled=false 时透传)。
|
||||
Security middleware.SecurityHeadersConfig
|
||||
// CORS 是跨域中间件配置(cfg-gated;Enabled=false 时透传)。默认 off,
|
||||
// 避免误配破坏 SPA + WS 握手;需要时显式开启并配置 origin 白名单。
|
||||
CORS middleware.CORSConfig
|
||||
// MetricsHandler 为 nil 时不挂 /metrics;非 nil 时挂到 GET /metrics。
|
||||
// 暴露成本/会话数,必须经 MetricsAuthToken 门禁(见 NewRouter)。
|
||||
MetricsHandler http.Handler
|
||||
// MetricsAuthToken 非空时,/metrics 要求 Authorization: Bearer <token>
|
||||
// 或 ?token=<token> 匹配,否则 401。为空时 /metrics 不做令牌校验(仅
|
||||
// 适用于绑定内网 / 由反代鉴权的部署)。
|
||||
MetricsAuthToken string
|
||||
}
|
||||
|
||||
// NewRouter builds the application's chi.Router with the standard
|
||||
@@ -36,6 +48,10 @@ func NewRouter(deps RouterDeps) chi.Router {
|
||||
|
||||
// 所有中间件必须在注册路由之前添加(chi 的强制要求)。
|
||||
r.Use(middleware.RequestID)
|
||||
// 安全头与 CORS 紧随 RequestID、在路由挂载之前;二者均 cfg-gated,
|
||||
// Enabled=false 时为透传,默认行为与历史一致。
|
||||
r.Use(middleware.SecurityHeaders(deps.Security))
|
||||
r.Use(middleware.CORS(deps.CORS))
|
||||
if deps.Logger != nil {
|
||||
r.Use(middleware.Recover(deps.Logger))
|
||||
r.Use(middleware.Logger(deps.Logger))
|
||||
@@ -61,9 +77,35 @@ func NewRouter(deps RouterDeps) chi.Router {
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
})
|
||||
|
||||
// /metrics(Prometheus):admin-gated via static bearer token. 挂在 SPA
|
||||
// NotFound 之前,确保未匹配请求不会落到 SPA fallback。
|
||||
if deps.MetricsHandler != nil {
|
||||
token := deps.MetricsAuthToken
|
||||
mh := deps.MetricsHandler
|
||||
r.Get("/metrics", func(w http.ResponseWriter, req *http.Request) {
|
||||
if token != "" && !metricsTokenOK(req, token) {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
mh.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
if deps.SPAHandler != nil {
|
||||
r.NotFound(deps.SPAHandler.ServeHTTP)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// metricsTokenOK 校验 /metrics 请求是否携带匹配的令牌(Authorization: Bearer
|
||||
// <token> 或 ?token=<token>)。
|
||||
func metricsTokenOK(req *http.Request, token string) bool {
|
||||
const prefix = "Bearer "
|
||||
if h := req.Header.Get("Authorization"); len(h) > len(prefix) && h[:len(prefix)] == prefix {
|
||||
if h[len(prefix):] == token {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return req.URL.Query().Get("token") == token
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user