Files
mce/internal/middleware/csrf.go
Victor_Jay 97adf54d6d fix: golangci-lint 零告警通过 (57→0) + gofumpt/goimports 全量格式化
## CI 修复 (P0/P1)

P0 — 编译阻塞:
  - interfaces.go: postUseCase ISP 接口移除不用的 Create/Update/Delete

P1 — 必须修复:
  - ST1000: 为 13 个包添加包注释 (common/config/model/service/...)
  - ST1005: redis_store.go 全部错误消息改为小写开头
  - errcheck (19处): defer Close()→闭包忽略, notifier.Create→_=, r.Run→检查error
  - errorlint (9处): switch-on-error→errors.Is 链, ==→errors.Is
  - ST1020/ST1022: 导出符号注释以符号名开头

P2 — 安全评审:
  - gosec (12处): G203/G301/G304/G306 添加 nolint 注释并附理由

P3 — 清理:
  - unused: 移除 hasUnicode/energyStore/current/energyAdminUseCase
  - gofumpt + goimports 全量格式化 (35+ 文件)
2026-06-22 02:27:35 +08:00

62 lines
1.5 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 提供 HTTP 中间件认证、授权、CSRF、安全头、限流等。
package middleware
import (
"crypto/subtle"
"log"
"net/http"
"metazone.cc/mce/internal/config"
"github.com/gin-gonic/gin"
)
const (
csrfCookieName = "mlb_csrf"
csrfHeaderName = "X-CSRF-Token"
csrfMetaName = "csrf_token"
)
// CSRF 中间件Double Submit Cookie 模式
func CSRF(cfg *config.Config) gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method == http.MethodGet ||
c.Request.Method == http.MethodHead ||
c.Request.Method == http.MethodOptions {
c.Next()
return
}
cookieToken, err := c.Cookie(csrfCookieName)
if err != nil || cookieToken == "" {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"success": false, "message": "CSRF 验证失败",
})
return
}
headerToken := c.GetHeader(csrfHeaderName)
if headerToken == "" {
headerToken = c.PostForm(csrfMetaName)
}
if headerToken == "" {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"success": false, "message": "CSRF 验证失败:缺少令牌",
})
return
}
if subtle.ConstantTimeCompare([]byte(cookieToken), []byte(headerToken)) != 1 {
log.Printf("[CSRF] MISMATCH | path=%s | cookie_len=%d | header_len=%d",
c.Request.URL.Path, len(cookieToken), len(headerToken))
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"success": false, "message": "CSRF 验证失败",
})
return
}
c.Set(csrfMetaName, cookieToken)
c.Next()
}
}