用于gin框架的CORS中间件(当然,用在其他的框架和语言中相应的Header头设置和配置信息和应用原理都是一样的),解决Access-Control-Allow-Credentials true身份凭证和 Access-Control-Allow-Origin:
注意修改相关的origin为你自己的, chrome插件的ID获取方式见 http跨域网络请求中的CORS(跨源资源共享) 那些事 -- HTTP跨域请求, chrome插件跨域请求使用详解, origin格式,origin通配符等-CSDN博客
- app:
- baseUrl: http://localhost:8080
-
- # 安全配置
- security:
- # api接口允许跨域调用的origin列表 格式 {scheme}://{域名端口或扩展ID} 可以使用通配符 * 或者? , 注意域名最后不带/斜杠
- corsAllowOrigins:
- - "http://localhost"
- - "http://localhost:8080"
- - "*.tekin.cn"
- - "*.yunnan.ws"
- - "chrome-extension://*" # 这个是在chrome扩展里面调用的域 * 表示允许所有的扩展调用, 只允许指定扩展,如: "chrome-extension://iflfjlikpkacloanbaaokocoafabjndg"
- corsAllowHeaders: "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id"
注意下面的代码中使用了viper来读取yaml中的配置信息,如果你使用其他配置信息读取方式,只需要修改viper相关的配置信息读取代码即可。
strutils字符串模式匹配工具库安装: go get -u github.com/tekintian/strutils
- package middleware
-
- import (
- "net/http"
-
- "github.com/gin-gonic/gin"
- "github.com/tekintian/strutils"
- "github.com/spf13/viper"
- )
- // gin CORS middleware 应用于gin框架的CORS中间件
- // @author tekintian@gmail.com
- func SecurityCORS(c *gin.Context) {
- method := c.Request.Method
- // 放行所有OPTIONS方法
- if method == "OPTIONS" {
- c.AbortWithStatus(http.StatusNoContent)
- return // 直接退出当前请求
- }
- // 获取当前请求的origin; 地址形式: scheme://domain 如 "http://localhost:8000" 注意origin的最后是没有 / 斜杠的
- origin := c.GetHeader("Origin")
- // 如果请求origin在允许的origin之中,则直接将当前请求的origin设置为允许的origin
- if isAllowOrigin(origin) {
- c.Header("Access-Control-Allow-Origin", origin)
- } else {
- // 不在允许范围,将配置中的域名作为允许origin设置
- c.Header("Access-Control-Allow-Origin", viper.String("app.baseUrl"))
- }
- // 附带身份凭证的请求, 注意这里如果是true, 则 Access-Control-Allow-Origin 不允许使用 * 通配符
- c.Header("Access-Control-Allow-Credentials", "true")
- // 设定允许的请求方式
- c.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT,HEAD,PATCH")
- // 允许的请求头信息, 默认"Content-Type,X-CSRF-Token,Authorization,Token"
- c.Header("Access-Control-Allow-Headers", viper.String("security.corsAllowHeaders"))
- // 暴露头信息
- c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type, New-Token, New-Expires-At")
- // 处理请求
- c.Next()
- }
-
- // 检测当前origin是否是允许的origin
- func isAllowOrigin(origin string) bool {
- // origin为空时 非跨域请求,直接放行
- if origin == "" {
- return true
- }
- corsAllowOrigins := viper.GetStringSlice("security.corsAllowOrigins")
- for _, v := range corsAllowOrigins {
- if v == origin || strutils.IsWmMatchingReg(origin, v) {
- return true
- }
- }
- return false
- }
- func main() {
- r := gin.New()
-
- // 使用自定义的CORS中间件
- r.Use(middleware.SecurityCORS)
-
- r.GET("/", func(c *gin.Context) {
- c.JSON(200, gin.H{
- "html": "Hello, world!",
- })
- })
-
- // 监听并在 0.0.0.0:8080 上启动服务
- r.Run(":8080")
- }