Files
Edu/services/api-gateway/internal/middleware/security.go
SpecialX 4307f6b73c feat(api-gateway): 实现 W1-W8 网关硬化与 P2-P5 路由扩展
依据 coord-final-decisions §3.8 W1-W8 裁决与
president-final-rulings §2.15/§2.16/§2.19 完整实现网关硬化:

- W1/W2: 错误码 GW_ 前缀 + ActionState 信封响应体
- W3: 全量替换为 log/slog 结构化日志
- W4: /readyz 并行 ping 9 下游 + 软失败规则
- W5: 7 个业务 Prometheus 指标 + /metrics 端点
- W6: tracer 资源属性补全(name/version/env/host)
- W7: DevMode=true && ENV=production panic 防护
- W8: 保持共享 downstream 熔断

P2 RS256 升级:接入 shared-go/jwks.Fetcher(TTL 5min)。
P2.7+P3-P5 路由扩展:student/parent/messages/dashboard。
文档同步:README/01/02/known-issues,arch.db 已更新。
质量校验:go vet + build + test 均通过。
2026-07-10 18:15:48 +08:00

50 lines
1.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
)
// SecurityHeaders 设置安全响应头中间件。
// 设置X-Content-Type-Options: nosniff
//
// X-Frame-Options: DENY
// Referrer-Policy: strict-origin-when-cross-origin
// Strict-Transport-Security: max-age=31536000; includeSubDomains
// Content-Security-Policy: default-src 'self'
// 移除 Server 头
func SecurityHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
h := c.Writer.Header()
h.Set("X-Content-Type-Options", "nosniff")
h.Set("X-Frame-Options", "DENY")
h.Set("Referrer-Policy", "strict-origin-when-cross-origin")
h.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
h.Set("Content-Security-Policy", "default-src 'self'")
h.Del("Server")
c.Next()
// 响应处理结束后再次移除 Server 头,防止处理过程中被写入
c.Writer.Header().Del("Server")
}
}
// RequestBodyLimit 限制请求体大小中间件。
// 超限时返回 413 + ActionState 信封W1/W2 裁决):
//
// {"success":false,"error":{"code":"GW_REQUEST_TOO_LARGE","message":"..."}}
//
// 通过 Content-Length 预检 + http.MaxBytesReader 双重保障:
// - Content-Length 预检已知大小的请求体立即拒绝JSON 信封响应)
// - MaxBytesReader流式请求体无 Content-Length读取超限时由标准库返回 413
func RequestBodyLimit(maxBytes int64) gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.ContentLength > maxBytes {
abortGW(c, http.StatusRequestEntityTooLarge, "GW_REQUEST_TOO_LARGE", "request body too large")
return
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBytes)
c.Next()
}
}