CORS全名為Cross-Origin Resource Sharing 跨來源資源共用,是種使用額外HTTP Header令目前瀏覽網站的使用者代理能夠取得其他網域四奇異資源的機制,當使用者代理乞求一個不是當前文件來源的資源(different domain, different protocol or different port...etc)時,會建立一個跨來源請求(Cross-Orgin HTTP Request)。
像是目前前後端分離的開發方式、前端頁面CSS、Image以及Script的Import以及CDN等,都是跨來源請求的例子,而基於安全性考量,這些Request都會受到限制。如果不使用CORS的Header將不能請求不同網域的HTTP資源。
CORS機制使我們能夠安全有效地進行跨網域請求,那什麼類型的requests會需要啟用CORS支援呢
abc.com
到 123.com
abc.com
到 cde.abc.com
abc.com
到 abc.com:8888
https://abc.com
到 http://abc.com
CORS Request可分為兩種,簡單請求與非簡單請求
如果以下條件皆符合,那該HTTP 請求為簡單請求:
GET
、HEAD
和 POST
請求的 API 資源所發出的。POST
方法請求,則必須包含 Origin
標頭。text/plain
、multipart/form-data
或 application/x-www-form-urlencoded
。對於簡單的跨來源 POST
方法請求,來自您資源的回應需要包括標頭 Access-Control-Allow-Origin
,其中標頭金鑰的值會設為 '*'
(任何來源),或設定為允許存取該資源的來源。
所有其他跨來源 HTTP 請求都是非簡單請求。如果您的 API 資源接收非簡單請求,您將需要啟用 CORS 支援。
go get github.com/gin-contrib/cors
func main() {
server := gin.Default()
corsConfig := cors.DefaultConfig()
corsConfig.AllowAllOrigins = true
server.Use(cors.New(corsConfig))
server.Run()
}
AllowAllOrigins
: 允許所有的CORS請求func main() {
server := gin.Default()
corsConfig := cors.DefaultConfig()
corsConfig.AllowOrigins = []string{"https://google.com", "https://facebook.com"}
corsConfig.AllowMethods = []string{"GET", "POST", "PUT"}
corsConfig.AllowHeaders = []string{"Authorization", "Origin"}
corsConfig.AllowCredentials = true
corsConfig.ExposeHeaders = []string{"Content-Length"}
corsConfig.MaxAge = 12 * time.Hour
server.Use(cors.New(corsConfig))
}
這邊講解一下幾個主要的設定:
AllowOrigins
: 允許的domainAllowMethods
: 允許的HTTP MethodAllowHeaders
: 允許的Header 信息AllowCredentials
: 是否允許請求包含驗證憑證ExposeHeaders
: 允許暴露的Header信息MaxAge
: 可被存取的時間接下來我們將CORS Settings包裝成一個Middleware讓 gin.Default()
做使用。
app/middleware/cors.go
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()
}
}
main.go
gin這邊記得要調用這個middleware,如此一來就完成了。
server.Use(middleware.CORSMiddleware())
由於上個章節剛剛結束了JWT實作在Gin上的部分,因此這章節立馬來解說使用JWT Token上常常會遇到的一個Issue 跨域問題! 那這邊除了解說CORS原理外,同時也立馬寫了個CORS的Middleware並加進Gin中,完成實作。
程式碼的部分我也會放到下方連結,有興趣者歡迎Pull來學習或使用。
https://github.com/Neskem/Ironman-2021/tree/Day-22
https://buddhiv.medium.com/what-is-cors-or-cross-origin-resource-sharing-eccbfacaaa30
https://docs.aws.amazon.com/zh_tw/apigateway/latest/developerguide/how-to-cors.html