From 3e1c04c3487c364a0b597ee0734e389872c880b5 Mon Sep 17 00:00:00 2001 From: ShadowWalker Date: Fri, 10 Dec 2021 22:56:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20CORS=E7=BB=84=E4=BB=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=BD=BF=E7=94=A8=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=9B=B4=E7=81=B5=E6=B4=BB=E7=9A=84=E9=85=8D=E7=BD=AE=E5=A4=84?= =?UTF-8?q?=E7=90=86=E8=B7=A8=E5=9F=9F=E7=9A=84=E9=80=BB=E8=BE=91;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/config.docker.yaml | 16 ++++++++++++ server/config.yaml | 16 +++++++++++- server/config/config.go | 3 +++ server/config/cors.go | 14 +++++++++++ server/initialize/router.go | 5 ++-- server/middleware/cors.go | 49 ++++++++++++++++++++++++++++++++++++- 6 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 server/config/cors.go diff --git a/server/config.docker.yaml b/server/config.docker.yaml index a5a72c50..8466fc05 100644 --- a/server/config.docker.yaml +++ b/server/config.docker.yaml @@ -135,3 +135,19 @@ Timer: { tableName: "sys_operation_records" , compareField: "created_at", interval: "2160h" }, #{ tableName: "log2" , compareField: "created_at", interval: "2160h" } ] + +# 跨域配置 +# 需要配合 server/initialize/router.go#L32 使用 +cors: + mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 + whitelist: + - allow-origin: example1.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 + - allow-origin: example2.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 diff --git a/server/config.yaml b/server/config.yaml index 97b0bcc6..4ad8e3d6 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -179,4 +179,18 @@ Timer: #{ tableName: "log2" , compareField: "created_at", interval: "2160h" } ] - +# 跨域配置 +# 需要配合 server/initialize/router.go#L32 使用 +cors: + mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 + whitelist: + - allow-origin: example1.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 + - allow-origin: example2.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 diff --git a/server/config/config.go b/server/config/config.go index 5668edc8..dae3571f 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -23,4 +23,7 @@ type Server struct { Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"` Timer Timer `mapstructure:"timer" json:"timer" yaml:"timer"` + + // 跨域配置 + Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"` } diff --git a/server/config/cors.go b/server/config/cors.go new file mode 100644 index 00000000..7fba9934 --- /dev/null +++ b/server/config/cors.go @@ -0,0 +1,14 @@ +package config + +type CORS struct { + Mode string `mapstructure:"mode" json:"mode" yaml:"mode"` + Whitelist []CORSWhitelist `mapstructure:"whitelist" json:"whitelist" yaml:"whitelist"` +} + +type CORSWhitelist struct { + AllowOrigin string `mapstructure:"allow-origin" json:"allow-origin" yaml:"allow-origin"` + AllowMethods string `mapstructure:"allow-methods" json:"allow-methods" yaml:"allow-methods"` + AllowHeaders string `mapstructure:"allow-headers" json:"allow-headers" yaml:"allow-headers"` + ExposeHeaders string `mapstructure:"expose-headers" json:"expose-headers" yaml:"expose-headers"` + AllowCredentials bool `mapstructure:"allow-credentials" json:"allow-credentials" yaml:"allow-credentials"` +} diff --git a/server/initialize/router.go b/server/initialize/router.go index 79cb2c2d..30937c18 100644 --- a/server/initialize/router.go +++ b/server/initialize/router.go @@ -29,8 +29,9 @@ func Routers() *gin.Engine { Router.StaticFS(global.GVA_CONFIG.Local.Path, http.Dir(global.GVA_CONFIG.Local.Path)) // 为用户头像和文件提供静态地址 // Router.Use(middleware.LoadTls()) // 打开就能玩https了 global.GVA_LOG.Info("use middleware logger") - // 跨域 - //Router.Use(middleware.Cors()) // 如需跨域可以打开 + // 跨域,如需跨域可以打开下面的注释 + // Router.Use(middleware.Cors()) // 直接放行全部跨域请求 + //Router.Use(middleware.CorsByRules()) // 按照配置的规则放行跨域请求 global.GVA_LOG.Info("use middleware cors") Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) global.GVA_LOG.Info("register swagger handler") diff --git a/server/middleware/cors.go b/server/middleware/cors.go index 68f6651f..fa1c6e2f 100644 --- a/server/middleware/cors.go +++ b/server/middleware/cors.go @@ -1,11 +1,13 @@ package middleware import ( + "github.com/flipped-aurora/gin-vue-admin/server/config" + "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/gin-gonic/gin" "net/http" ) -// 处理跨域请求,支持options访问 +// Cors 直接放行所有跨域请求并放行所有 OPTIONS 方法 func Cors() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method @@ -24,3 +26,48 @@ func Cors() gin.HandlerFunc { c.Next() } } + +// CorsByRules 按照配置处理跨域请求 +func CorsByRules() gin.HandlerFunc { + // 放行全部 + if global.GVA_CONFIG.Cors.Mode == "allow-all" { + return Cors() + } + return func(c *gin.Context) { + whitelist := checkCors(c.GetHeader("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) + c.Header("Access-Control-Expose-Headers", whitelist.ExposeHeaders) + if whitelist.AllowCredentials { + c.Header("Access-Control-Allow-Credentials", "true") + } + } + + // 严格白名单模式且未通过检查,直接拒绝处理请求 + if whitelist == nil && global.GVA_CONFIG.Cors.Mode == "strict-whitelist" { + c.AbortWithStatus(http.StatusForbidden) + } else { + // 非严格白名单模式,无论是否通过检查均放行所有 OPTIONS 方法 + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(http.StatusNoContent) + } + } + + // 处理请求 + c.Next() + } +} + +func checkCors(currentOrigin string) *config.CORSWhitelist { + for _, whitelist := range global.GVA_CONFIG.Cors.Whitelist { + // 遍历配置中的跨域头,寻找匹配项 + if currentOrigin == whitelist.AllowOrigin { + return &whitelist + } + } + return nil +} From e01d52b771518ed837b0c40492ef8b8f5bbf9ce7 Mon Sep 17 00:00:00 2001 From: ShadowWalker Date: Sat, 11 Dec 2021 00:27:51 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=B8=A5=E6=A0=BC=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E6=A8=A1=E5=BC=8F=E6=8B=A6=E6=88=AA=E4=BA=86=E5=81=A5?= =?UTF-8?q?=E5=BA=B7=E6=A3=80=E6=9F=A5=E5=AF=BC=E8=87=B4=E5=81=A5=E5=BA=B7?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E9=80=BB=E8=BE=91=E5=A4=B1=E6=95=88=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/middleware/cors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/middleware/cors.go b/server/middleware/cors.go index fa1c6e2f..99664b7e 100644 --- a/server/middleware/cors.go +++ b/server/middleware/cors.go @@ -48,7 +48,7 @@ func CorsByRules() gin.HandlerFunc { } // 严格白名单模式且未通过检查,直接拒绝处理请求 - if whitelist == nil && global.GVA_CONFIG.Cors.Mode == "strict-whitelist" { + if whitelist == nil && global.GVA_CONFIG.Cors.Mode == "strict-whitelist" && !(c.Request.Method == "GET" && c.Request.URL.Path == "/health") { c.AbortWithStatus(http.StatusForbidden) } else { // 非严格白名单模式,无论是否通过检查均放行所有 OPTIONS 方法