iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0

What is CORS

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資源。

https://ithelp.ithome.com.tw/upload/images/20211007/20129737DljZ9D0421.png

CORS機制使我們能夠安全有效地進行跨網域請求,那什麼類型的requests會需要啟用CORS支援呢

  • 不同的網域:像是從 abc.com123.com
  • 不同的子網域:像是從 abc.comcde.abc.com
  • 不同的port:像是從 abc.comabc.com:8888
  • 不同的通訊協定:像是從 https://abc.comhttp://abc.com

CORS Request可分為兩種,簡單請求與非簡單請求

如果以下條件皆符合,那該HTTP 請求為簡單請求:

  • 它是針對只允許 GETHEAD 和 POST 請求的 API 資源所發出的。
  • 如果它是 POST 方法請求,則必須包含 Origin 標頭。
  • 請求承載內容類型為 text/plainmultipart/form-data 或 application/x-www-form-urlencoded
  • 請求不包含自訂標頭。

對於簡單的跨來源 POST 方法請求,來自您資源的回應需要包括標頭 Access-Control-Allow-Origin,其中標頭金鑰的值會設為 '*'(任何來源),或設定為允許存取該資源的來源。

所有其他跨來源 HTTP 請求都是非簡單請求。如果您的 API 資源接收非簡單請求,您將需要啟用 CORS 支援。

Gin with CORS

Installation

go get github.com/gin-contrib/cors

Allow all CORS Resource

func main() {
  server := gin.Default()
	corsConfig := cors.DefaultConfig()
	corsConfig.AllowAllOrigins = true
	server.Use(cors.New(corsConfig))
  server.Run()
}
  • AllowAllOrigins: 允許所有的CORS請求

Allow Specific CORS Resource

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: 允許的domain
  • AllowMethods: 允許的HTTP Method
  • AllowHeaders: 允許的Header 信息
  • AllowCredentials: 是否允許請求包含驗證憑證
  • ExposeHeaders: 允許暴露的Header信息
  • MaxAge: 可被存取的時間

Gin with CORS Middleware

接下來我們將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())

Summary

由於上個章節剛剛結束了JWT實作在Gin上的部分,因此這章節立馬來解說使用JWT Token上常常會遇到的一個Issue 跨域問題! 那這邊除了解說CORS原理外,同時也立馬寫了個CORS的Middleware並加進Gin中,完成實作。

程式碼的部分我也會放到下方連結,有興趣者歡迎Pull來學習或使用。

https://github.com/Neskem/Ironman-2021/tree/Day-22

Reference

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


上一篇
Day21 Gin with JWT
下一篇
Day23 Gin with i18n
系列文
fmt.Println("從零開始的Golang生活")30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言