跨域请求cookie资源共享详解

2,011 阅读2分钟

HTTP Cookie是服务器发送得用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时自动携带并发送到服务器上。换句话说,http请求携带cookie只发生在同源请求时。对于跨域请求,要携带cookie该怎么解决这个问题呢?

技术背景:@vue/cli ^3 + axios + typescript + webpack ^4

HTTP请求分为简单请求和预检查请求,具体可以参考 跨域资源共享CORS详解

HTTP请求头中几个重要的标志:

  • General中:
    • Request URL:请求接口
    • Remote Address:请求的服务器地址
  • Request Headers:
    • Accept:接收信息的格式,application/json, text/plain
    • Origin:简单请求会自动加上的请求源
  • Response Headers
    • Access-Control-Allow-Credentials:可选的布尔值,表示是否允许发送cookie。设为true,则服务器允许cookie可以包含在请求中,否则不包括在cors请求中。

示例1(子域名不同):

为了实现单点登录,网站A:child.aaa.com要跳转到主站B:www.aaa.com/login进行登录,并在登录后再次跳回child.aaa.com,此时在往网站A种下domain为aaa.com的cookie,之后再网站A发送主站B:www.aaa.com接口的Http请求并需要携带该cookie获取access_token以验证用户身份。


解决方案:

1. withCredentials: true

除了服务器要同一可发送cookie之外,客户端发起http请求时也需要同步打开withCredentials属性。axios中具体写法如下:

axios.defaults.withCredentials = true

示例2(主域名不同):

为了实现单点登录,网站A:www.aaa.com要跳转到主站B:www.bbb.com/login进行登录,并在登录后再次跳回www.aaa.com,此时在往网站A种下domain为home.com的cookie,之后再网站A发送主站B:www.bbb.com接口的Http请求并需要携带该cookie获取access_token以验证用户身份。

解决方案:

1. 首先withCredentials: true同上。

其次可以使用webpack的proxy代理

devServer: {
    disableHostCheck: true,   // 如果存在host、hosts的交叉请求,则需要忽略webpack中host检查
    proxy: {
        'api/': {
            target: 'www.bbb.com', // 最终请求的目标host
            changeOrigin: true, // 默认false,保存原host的header
            secure: false   // 默认true时,不接受https协议且证书无效的后端服务器
        }
    }
}

这种方案由于不检查请求头协议,会存在CSRP攻击,只适合开发阶段使用。

2. 服务器域名解析

可以在服务器层,将aaa.com域名解析到bbb.com域名上,及在跳转到主站B时,可以请求www.aaa.com/login后有服务器重定向到www.bbb.com/login,接口请求时的原理同,此时调回子站A时cookie的domain是aaa.com,而接口请求时也会自主携带上cookie,不受浏览器跨域影响。