Cookie重新认知2,跨域Cookie

拖延症专家 · · 1540 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

距离上一次cookie学习快两个月了,这几天想给自己的网站写一个用户系统,或者说权限系统。因为后端是使用Golang的net/http标准库实现的,所以说好多东西都要自己实现。所以从新来回顾下cookie机制好方便对前后端状态管理和权限验证有更为深入得了解。

cookie的收发机制在认知1中做了详细得介绍并附有实验。本次记录的主要是关于Ajax跨域时遇到的一些cookie相关的问题。
首先当Ajax请求发生跨域时默认是不会携带cookie的,如果想要携带cookie需要手动为Ajax指定withCredentials属性。代码实现如下:

  1. 原生Ajax
      var xmlHttpRequest = new XMLHttpRequest()
      xmlHttpRequest.withCredentials = true //重点是这一行
      xmlHttpRequest.open('get','http://127.0.0.1:53000/getPit')
      xmlHttpRequest.onreadystatechange=function(){
        if(xmlHttpRequest.readyState==4){
          if(xmlHttpRequest.status==200||xmlHttpRequest.status==304){
            window.console.log(JSON.parse(xmlHttpRequest.response))
          }
        }
      }
      xmlHttpRequest.send()
  1. Jquery
    $.get({
        type:'get',
        url:'http://127.0.0.1:53000/detect',
        dataType: "json",
        crossDomain:true,//指明需要跨域
        //xhrFiled告诉Jquery跨域时携带cookie
        xhrFields:{
          withCredentials:true
        },
        success:function(res){
          window.console.log(res)
        }
      })
  1. axios
      //告诉axios跨域时携带cookie
      this.axios.defaults.withCredentials = true
      this.axios.get("http://127.0.0.1:53000/getPit").then(e=>{
        window.console.log(e)
      })

可以看到主要是为发出Ajax请求的XMLHttpRequest对象的withCredentials属性指定为true,当然只有前台指定了该参数是不行的,后台需要做对应的配置,后台根据开发语言的不同配置也有所出入,尤其是使用了一些Web开发框架后框架可能会对应的配置方式。但原理都是向http响应头中写入 Access-Control-Allow-Credentials:true属性这里我是用的是Golang net/http标准库代码为:

    //放行所有跨域请求
    ref:=strings.TrimSuffix(r.Referer(),"/")
    w.Header().Set("Access-Control-Allow-Origin", ref)
    w.Header().Set("Access-Control-Allow-Credentials", "true")

这里需要注意一旦明跨域需要携带cookie放行跨域的Access-Control-Allow-Origin属性就不能使用*通配符了,而是需要指定具体域名且必须为你发起请求的域名。我这里代码中的r.Referer()函数的作用便是获取发情请求的域名。r是gohttp.Request指针。

这样配置完成后Ajax请求就能够正常携带cookie向后端发起跨域请求了。但现在还存在一些问题

  1. 前端不能使用document.cookie操作,原因是后台返回的cookie的domain属性与前台域名不相同,该cookie并不会存储在当前页面的cookie中。但是发起请求的url与该cookie的domain相同。这里做了个简单测试。
    前端Ajax请求参照之前的代码,后端部分代码为:
func GetPit(c *engine.Context) {
    fmt.Println(c.Req.Cookies())
    cookie := http.Cookie{
        Name:    "user",
        Value:   "wxm530",
        Path:    "/",
        Expires: time.Now().AddDate(1, 0, 0),
    }
    http.SetCookie(c.Writer, &cookie)
    c.Json(nil)
}

现在发起请求两次


从图中可以看到两次请求均发送成功且第一次没有携带cookie,合情合理,第二此请求浏览器成功将服务器设置的cookie返回给后台,但是浏览器cookie指示当前页面并没有存储cookie这就是前面所说的这个cookie被存储在别的域名下,并且使用chrome可以很方便的看到那就是地址栏的起始位置有一个小叹号。

可以看到该cookie被存储在了127.0.0.1中。
这里我曾想过直接从Response Headers中获取该cookie。但翻遍响应对象也没有找到,后来想想也是隐私信息怎么能随意获取呢。但我翻看XMLHttpRequest原型时发现了这个两个方法

见名知意getAllResponseHeaders就是获取全部响应头那。。。getResponseHeader岂不是能获取我想要的Header 于是就有了下面这一行代码

window.console.log(xmlHttpRequest.getResponseHeader('Set-Cookie'))

年轻 哈哈哈哈哈哈哈哈哈

  1. 相对与http协议来说,未来Chrome可能不能使用现有方法传cookie,原因是我在实验时收到了Chrome的这样一条警告。如下图

    意思就是说我服务器设置的cookie没有SameSite属性,未来Chrome将不会发送没有SameSite属性的跨域cookie,并且设置了SameSite属性的同时也要带Secure属性所以我修改了后台代码。
func GetPit(c *engine.Context) {
    fmt.Println(c.Req.Cookies())
    cookie := http.Cookie{
        Name:    "user",
        Value:   "wxm530",
        Path:    "/",
        SameSite: http.SameSiteNoneMode,
        Secure: true,
        Expires: time.Now().AddDate(1, 0, 0),
    }
    http.SetCookie(c.Writer, &cookie)
    c.Json(nil)
}

SameSite共有三个可选值,可参考阮一峰大佬的解释
但事情远远没有这么简单重启服务端跑一下


什么,Application中可以看到cookie了domain还不相同???但同样可以注意到这个cookie颜色好像不太一样,这个cookie它中暑了emmm,

把鼠标放在那个叹号上就能看到,这个cookie它有Secure属性但它不是用安全连接接收的,后来又去查了下Secure属性的作用:标识该cookie只能使用https协议发送。好吧改天把服务器上证书拔下来试试吧。


至此对Cookie又有了更深入的了解,希望也能再能写一篇Cookie重新认知3吧。
——2020/5/22 22:35,大幻梦森罗万象狂气断罪眼\ (•◡•) /


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:拖延症专家

查看原文:Cookie重新认知2,跨域Cookie

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1540 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传