带cookie跨域问题的思路以及echo的解决方案

问题起因

前后端分离,前端要访问后端资源,而且需要携带cookie信息,这时碰到了跨域问题。一开始以为设置为允许跨域allow_origins为即可。可是浏览器还是拦截的请求,于是查看跨域规则,原来跨域allow_origins为时,只允许简单的跨域,比如get,post,但是如果携带cookie,则会出现失败。

思路

后来查看文档,原来按照跨域请求的规则,当跨域和来源一致时才可以携带cookie。详情见阮一峰的博客

echo框架中的解决办法

有了思路就好办了,echo框架中的跨域设置不够详细,做不到设置来源跨域。于是我修改了一下其中的跨域中间件,增加了一子域名的跨域。
实际上可以修改为,任意来源的跨域,但是这样就不能保证安全了,不过如果是做接口平台倒是可以这么办。
完整代码为:

package echo_cors

import (
    "net/http"
    "strconv"
    "strings"

    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

type (
    // CORSConfig defines the config for CORS middleware.
    CORSConfig struct {
        // Skipper defines a function to skip middleware.
        Skipper middleware.Skipper

        // AllowOrigin defines a list of origins that may access the resource.
        // Optional. Default value []string{"*"}.
        AllowOrigins []string `json:"allow_origins"`

        // AllowMethods defines a list methods allowed when accessing the resource.
        // This is used in response to a preflight request.
        // Optional. Default value DefaultCORSConfig.AllowMethods.
        AllowMethods []string `json:"allow_methods"`

        // AllowHeaders defines a list of request headers that can be used when
        // making the actual request. This in response to a preflight request.
        // Optional. Default value []string{}.
        AllowHeaders []string `json:"allow_headers"`

        // AllowCredentials indicates whether or not the response to the request
        // can be exposed when the credentials flag is true. When used as part of
        // a response to a preflight request, this indicates whether or not the
        // actual request can be made using credentials.
        // Optional. Default value false.
        AllowCredentials bool `json:"allow_credentials"`

        // ExposeHeaders defines a whitelist headers that clients are allowed to
        // access.
        // Optional. Default value []string{}.
        ExposeHeaders []string `json:"expose_headers"`

        // MaxAge indicates how long (in seconds) the results of a preflight request
        // can be cached.
        // Optional. Default value 0.
        MaxAge         int `json:"max_age"`
        AllowSubDomain bool
        MainDomain     string
        AllowAllHost   bool
    }
)

var (
    // DefaultCORSConfig is the default CORS middleware config.
    DefaultCORSConfig = CORSConfig{
        Skipper:      middleware.DefaultSkipper,
        AllowOrigins: []string{"*"},
        AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
    }
)

// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
// See: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
func CORS() echo.MiddlewareFunc {
    return CORSWithConfig(DefaultCORSConfig)
}

// CORSWithConfig returns a CORS middleware with config.
// See: `CORS()`.
func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
    // Defaults
    if config.Skipper == nil {
        config.Skipper = DefaultCORSConfig.Skipper
    }
    if len(config.AllowOrigins) == 0 {
        config.AllowOrigins = DefaultCORSConfig.AllowOrigins
    }
    if len(config.AllowMethods) == 0 {
        config.AllowMethods = DefaultCORSConfig.AllowMethods
    }

    allowMethods := strings.Join(config.AllowMethods, ",")
    allowHeaders := strings.Join(config.AllowHeaders, ",")
    exposeHeaders := strings.Join(config.ExposeHeaders, ",")
    maxAge := strconv.Itoa(config.MaxAge)

    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            if config.Skipper(c) {
                return next(c)
            }

            req := c.Request()
            res := c.Response()
            origin := req.Header.Get(echo.HeaderOrigin)
            allowOrigin := ""

            // Check allowed origins
            for _, o := range config.AllowOrigins {
                if o == "*" || o == origin {
                    allowOrigin = o
                    break
                }
            }
            if config.AllowSubDomain && config.MainDomain != "" {
                if strings.Contains(origin, config.MainDomain) {
                    allowOrigin = origin
                }
            }
            if config.AllowAllHost {
                allowOrigin = c.Scheme()+"://"+req.Host
            }
            // Simple request
            if req.Method != echo.OPTIONS {
                res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
                res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
                if config.AllowCredentials {
                    res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
                }
                if exposeHeaders != "" {
                    res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
                }
                return next(c)
            }

            // Preflight request
            res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
            res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
            res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
            res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
            res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
            if config.AllowCredentials {
                res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
            }
            if allowHeaders != "" {
                res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
            } else {
                h := req.Header.Get(echo.HeaderAccessControlRequestHeaders)
                if h != "" {
                    res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
                }
            }
            if config.MaxAge > 0 {
                res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
            }
            return c.NoContent(http.StatusNoContent)
        }
    }
}

用法

已经放到github
这里增加了三个变量,AllowSubDomain,允许二级域名,MainDomain根域名,AllowAllHost 允许所有的跨域

  • CORSWithConfig(CORSConfig{AllowCredentials:true,AllowSubDomain:true,MainDomain:"main.com"}) 允许子域名跨域
  • CORSWithConfig(CORSConfig{AllowCredentials:true,AllowAllHost:true})
    对于js,也要做对应修改,axios的修改如下:
const Axios = axios.create({
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    withCredentials: true
});


Axios.interceptors.request.use(
    config => {
        if (config.method === 'post' || config.method === 'put') {
            if (config.data) {
                var queryString = Object.keys(config.data)
                    .map(key => {
                        return encodeURIComponent(key) + '=' + encodeURIComponent(config.data[key]);
                    })
                    .join('&');
                config.data = queryString;
            }
            return config;
        }
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);

转载于:https://www.cnblogs.com/xdao/p/9343442.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值