| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- package handler
- import (
- "context"
- "net/http"
- "strings"
- "time"
- "github.com/Wei-Shaw/sub2api/internal/pkg/ip"
- "github.com/Wei-Shaw/sub2api/internal/securityaudit"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- )
- // checkGroupSecurityPolicy 是分组安全策略在网关审计链中的唯一入口,
- // 由 runSecurityAudit 在全局审计之前调用。开关关闭(默认)时为纯 no-op。
- // 返回 nil 表示放行;非 nil 且 AllowNextStage=false 时调用方必须拒绝请求。
- func checkGroupSecurityPolicy(c *gin.Context, securityPolicy *service.SecurityPolicyService, apiKey *service.APIKey, protocol, model string, body []byte) *securityaudit.Decision {
- if securityPolicy == nil || apiKey == nil {
- return nil
- }
- group := apiKey.Group
- if group == nil || !group.SecurityPolicyEnabled {
- return nil
- }
- mode := service.NormalizeSecurityPolicyMode(group.SecurityPolicyMode)
- verdict := securityPolicy.EvaluateRequest(c.Request.Context(), c, service.SecurityPolicyRequest{
- APIKey: apiKey,
- Protocol: protocol,
- Model: model,
- Endpoint: GetInboundEndpoint(c),
- Body: body,
- RequestID: c.Writer.Header().Get("X-Request-Id"),
- ClientIP: strings.TrimSpace(ip.GetClientIP(c)),
- UserAgent: c.GetHeader("User-Agent"),
- })
- if verdict == nil || verdict.Allowed {
- return nil
- }
- // 异步落库/封禁/邮件:本请求已决定拒绝,不阻塞响应。
- record := service.SecurityPolicyHitRecord{
- RequestID: c.Writer.Header().Get("X-Request-Id"),
- APIKey: apiKey,
- Protocol: protocol,
- Model: model,
- Endpoint: GetInboundEndpoint(c),
- Verdict: verdict,
- SessionMode: mode,
- }
- go func() {
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
- securityPolicy.RecordHit(ctx, record)
- }()
- status := http.StatusForbidden
- if status < 400 || status > 599 {
- status = http.StatusForbidden
- }
- return &securityaudit.Decision{
- Kind: securityaudit.DecisionBlock,
- HTTPStatus: status,
- ErrorCode: verdict.ErrorCode,
- ClientMessage: verdict.ClientMessage,
- AllowNextStage: false,
- }
- }
|