前言
在前后端分离的开发中,跨域问题一直是让开发者头疼的问题。今天我将分享一个基于 Gin 框架的 CORS 中间件实现,它提供了两种模式:全局放行和白名单控制,让跨域配置变得简单而安全。
核心功能
- 支持全局跨域放行
- 支持白名单模式
- 灵活的配置选项
- 健康检查接口豁免
实现方案
1. 配置文件设置
首先在配置文件中定义 CORS 相关配置:
cors:
mode: "strict-whitelist" # 可选: allow-all, strict-whitelist
whitelist:
- allow-origin: "http://localhost:8080"
allow-headers: "Content-Type,AccessToken,X-CSRF-Token,Authorization,Token"
allow-methods: "POST,GET,OPTIONS,DELETE,PUT"
expose-headers: "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers"
allow-credentials: true
2. 使用方法
在 main.go 中注册中间件:
package main
import (
"github.com/gin-gonic/gin"
"your-project/middleware"
)
func main() {
r := gin.Default()
// 使用CORS中间件
r.Use(middleware.CorsByRules())
// 路由配置
r.GET("/api/users", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "success"})
})
r.Run(":8080")
}
3. 两种使用模式
模式一:全局放行
适合开发环境或者简单应用:
// config.yaml
cors:
mode: "allow-all"
这种模式会允许所有跨域请求,配置简单,但安全性较低。
模式二:白名单模式
适合生产环境:
// config.yaml
cors:
mode: "strict-whitelist"
whitelist:
- allow-origin: "https://your-frontend.com"
allow-methods: "GET,POST,PUT,DELETE"
allow-credentials: true
这种模式只允许配置中指定的域名访问,安全性高。
实现细节解析
1. 全局放行模式
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT")
c.Header("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
2. 白名单模式
func CorsByRules() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.GetHeader("origin")
whitelist := checkCors(origin)
if whitelist != nil {
// 设置允许的跨域信息
c.Header("Access-Control-Allow-Origin", whitelist.AllowOrigin)
c.Header("Access-Control-Allow-Headers", whitelist.AllowHeaders)
c.Header("Access-Control-Allow-Methods", whitelist.AllowMethods)
// ... 其他header设置
}
// 处理OPTIONS请求
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
特色功能
1. 健康检查接口豁免
即使在严格模式下,健康检查接口也可以被访问:
if whitelist == nil && mode == "strict-whitelist" &&
!(c.Request.Method == "GET" && c.Request.URL.Path == "/health") {
c.AbortWithStatus(http.StatusForbidden)
}
2. 灵活的Header配置
支持自定义允许的Headers:
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id")
3. 支持Cookie跨域
通过配置允许携带认证信息:
c.Header("Access-Control-Allow-Credentials", "true")
最佳实践
1. 开发环境配置
cors:
mode: "allow-all" # 开发环境下使用全局放行
2. 生产环境配置
cors:
mode: "strict-whitelist"
whitelist:
- allow-origin: "https://prod.your-site.com"
allow-methods: "GET,POST,PUT,DELETE"
allow-credentials: true
- allow-origin: "https://admin.your-site.com"
allow-methods: "GET,POST"
allow-credentials: true
3. 前端调用示例
// axios配置
axios.defaults.withCredentials = true; // 允许携带cookie
const api = axios.create({
baseURL: 'http://your-api.com',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
}
});
安全建议
- 生产环境必须使用白名单模式
- 定期审查白名单配置
- 只允许必要的HTTP方法
- 谨慎配置 Allow-Credentials
- 使用HTTPS协议
性能优化
- 使用缓存存储白名单配置
- OPTIONS请求快速响应
- 避免复杂的判断逻辑
总结
这个CORS中间件设计简洁而强大,既可以在开发环境中快速使用,也能在生产环境中提供安全可靠的跨域控制。通过合理的配置,可以轻松解决前后端分离开发中的跨域问题。
参考资料
希望这篇文章能帮助你更好地理解和使用CORS中间件!如果有任何问题,欢迎在评论区讨论。