跳至主要内容

[gin] gin-cors 筆記

gin-contrib/cors @ github

使用 default 會碰到的問題

使用 cors.Default() 雖然會允許所有的 origins,但因為預設的 DefaultConfig 中的 AllowHeaders 並沒有允許 Authorization 的 header,因此如果想要使用 JWT 等其他方式做登入驗證會失敗

// https://github.com/gin-contrib/cors
func main() {
router := gin.Default()
// same as
// config := cors.DefaultConfig()
// config.AllowAllOrigins = true
// router.Use(cors.New(config))
router.Use(cors.Default())
router.Run()
}

cors.go @ github:檢視 DefaultConfig() 的內容

因此比較好的作法還是自行建立設定檔,或者使用 cors.DefaultConfig() 取得預設的設定後,再根據需求去改設定內容,要留意的地方有兩個:

  • AllowAllOrigins 設成 true 會開放所有 origin
  • AllowHeaders 記得有要 Authorization

其他設定包含:

  • AllowWildcard:設成 true 則可以允許 origin 中帶有 wildcard

建立預設的設定檔後再修改

// 在 middleware 中使用
router.Use(cors.New(auth.CorsConfig(config)))

// 定義 cors-config
func CorsConfig(conf *config.Configuration) cors.Config {
corsConf := cors.DefaultConfig()
corsConf.AllowAllOrigins = true
corsConf.AllowMethods = []string{"GET", "POST", "DELETE", "OPTIONS", "PUT"}
corsConf.AllowHeaders = []string{"Authorization", "Content-Type", "Upgrade", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host", "Access-Control-Request-Method", "Access-Control-Request-Headers"}
return corsConf
}

自行建立設定檔

// 在 middleware 中使用
router.Use(cors.New(auth.CorsConfig(config)))

// 定義 cors-config
func CorsConfig(conf *config.Configuration) cors.Config {

corsConf := cors.Config{
MaxAge: 12 * time.Hour,
AllowBrowserExtensions: true,
}

if mode.IsDev() {
// 在開發環境時,允許所有 origins、所有 methods 和多數的 headers
corsConf.AllowAllOrigins = true
corsConf.AllowMethods = []string{"GET", "POST", "DELETE", "OPTIONS", "PUT"}
corsConf.AllowHeaders = []string{"Authorization", "Content-Type", "Upgrade", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host"}
} else {
// 在正式環境時則根據設定檔調整
compiledOrigins := compileAllowedCORSOrigins(conf.Server.Cors.AllowOrigins)
corsConf.AllowMethods = []string{"GET", "POST", "DELETE", "OPTIONS", "PUT"}
corsConf.AllowHeaders = []string{"Authorization", "Content-Type", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host"}
corsConf.AllowOrigins = []string{"https://www.example.com"}
}

return corsConf
}

gin-cors Snippets

// ./auth/cors.go
package auth

// CorsConfig generates a config to use in gin cors middleware based on server configuration
func CorsConfig(conf *config.Configuration) cors.Config {
corsConf := cors.Config{
MaxAge: 12 * time.Hour,
AllowWildcard: conf.Server.Cors.AllowWildcard,
AllowBrowserExtensions: conf.Server.Cors.AllowBrowserExtensions,
AllowWebSockets: conf.Server.Cors.AllowWebSockets,
}

if mode.IsDev() {
corsConf.AllowAllOrigins = true
corsConf.AllowMethods = []string{"GET", "POST", "DELETE", "PATCH", "OPTIONS", "PUT"}
corsConf.AllowHeaders = []string{"Authorization", "Content-Type", "Upgrade", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host"}
} else {
corsConf.AllowOrigins = conf.Server.Cors.AllowOrigins
corsConf.AllowMethods = conf.Server.Cors.AllowMethods
corsConf.AllowHeaders = conf.Server.Cors.AllowHeaders
}

return corsConf
}

使用:

// ./router/router.go
package router
func Create(db *database.GormDatabase, config *config.Configuration) *gin.Engine {
router := gin.New()
router.Use(cors.New(auth.CorsConfig(config)))
router.Use(gin.Logger(), gin.Recovery())
}

原生的作法

Go gin framework CORS @ StackOverflow

還有另一種是直接中 ctx.Writer 的 Header 進行修改:

// https://stackoverflow.com/questions/29418478/go-gin-framework-cors

func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")

if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}

c.Next()
}
}