axe/internal/middleware/cors.go
2026-10-18 22:07:25 +03:00

67 lines
2.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"
"strings"
"github.com/gin-gonic/gin"
)
// ParseOrigins — разобрать CORS_ORIGINS: источники через запятую,
// пустые куски и пробелы отбрасываются. Пустая строка — пустой список,
// то есть ни один кросс-доменный запрос не получит заголовков.
func ParseOrigins(raw string) []string {
var out []string
for _, part := range strings.Split(raw, ",") {
if o := strings.TrimSpace(part); o != "" {
out = append(out, o)
}
}
return out
}
// CORS — заголовки для кросс-доменных запросов (микрофронт и разработка
// с отдельного origin).
//
// Безопасный дефолт: список разрешённых источников приходит из
// CORS_ORIGINS, и если он пуст — ничего не выдаём вовсе. Фронту на том же
// домене CORS не нужен, а чужому домену его просто не должно быть.
//
// Разрешённый origin получает точный свой адрес в Allow-Origin
// (не `*`: рядом Authorization, звёздочка запрещена спецификацией),
// Vary: Origin — чтобы кэши не смешали ответы для разных источников.
//
// Preflight-OPTIONS отвечает 204 и обрывается ДО авторизации: браузер
// спрашивает «можно ли» заранее, запроса с токеном ещё нет.
func CORS(allowed []string) gin.HandlerFunc {
allowedSet := make(map[string]bool, len(allowed))
for _, o := range allowed {
allowedSet[o] = true
}
return func(c *gin.Context) {
origin := c.GetHeader("Origin")
if origin == "" || !allowedSet[origin] {
// Без CORS-заголовков браузер сам закроет ответ — серверу
// ничего не нужно делать.
c.Next()
return
}
h := c.Writer.Header()
h.Set("Access-Control-Allow-Origin", origin)
h.Add("Vary", "Origin")
h.Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS")
h.Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Request-Id")
h.Set("Access-Control-Expose-Headers", "X-Request-Id")
// Кэш preflight: браузер не будет переспрашивать каждую минуту.
h.Set("Access-Control-Max-Age", "600")
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}