Js设置二级域名和顶级域名下共享Cookie

前言

今天在蘑菇博客进行登录的时候,发现一个BUG,就是在用户登录后,有登录信息,但是刷新页面后,就没有头像了,F12打开调试页面,查看token也没有了

开始感觉非常的怪异,以为是chrome的原因,因为token是存储在cookie中的,而且也设置了有效期为7天,不可能退出浏览器就删除了,但是在我点开一个页面的时候

发现cookie有出现了,而且用户也正常登录,后面经过排查发现,是因为cookie二级域名和顶级域名不共享的原因而引起的

原理

首先Js在设置cookie的时候,默认会存放在当前的域名下,因为我登录后,会返回www.moguit.cn的页面,同时附带token信息,那么我们的token也就值保存在了 www.moguit.cn页面,而我们通过浏览器输入www.moguit.cn其实访问的是moguit.cn的顶级域名

那么就会造成:二级子域名下的cookie和顶级域名不共享的。同理 a.example.com下设置cookie, 在b.example.com下也是无法正常使用的

要避免这样的原因,我们就需要设置cookie的domain

下面是关于cookie的一些配置

  • name Cookie的名称,Cookie一旦创建,名称便不可更改

  • value Cookie的值,如果值为Unicode字符,需要为字符编码。如果为二进制数据,则需要使用BASE64编码

  • maxAge Cookie失效的时间,单位秒。如果为整数,则该Cookie在maxAge秒后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为-1。

  • secure 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。

  • path Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。

  • domain 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。

  • comment 该Cookie的用处说明,浏览器显示Cookie信息的时候显示该说明。

  • version Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

我们通过domain的属性可能看到,当我们设置 .google.com的时候,那么以google.com结尾的域名都能够访问该cookie

那么如果我们想要让cookie进行共享的话,就必须以 .moguit.cn进行共享

host = location.host;
domainParts = host.split('.');
domainParts.shift();
domain = '.'+domainParts.join('.');

我们通过这段代码,就能够截取到顶级域名了,同时我们需要加上 .

image.png

完整的CookieUtil代码为:

/**
 * CookieUtil常用的一些工具类
 */

export function setCookie(name, value, days) {
  // var exp = new Date();
  // exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);
  // document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();

  var domain, domainParts, date, expires, host;

  if (days)
  {
    date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    expires = "; expires="+date.toGMTString();
  }
  else
  {
    expires = "";
  }

  host = location.host;
  if (host.split('.').length === 1)
  {
    // no "." in a domain - it's localhost or something similar
    document.cookie = name+"="+value+expires+"; path=/";
  }
  else
  {
    // Remember the cookie on all subdomains.
    //
    // Start with trying to set cookie to the top domain.
    // (example: if user is on foo.com, try to set
    //  cookie to domain ".com")
    //
    // If the cookie will not be set, it means ".com"
    // is a top level domain and we need to
    // set the cookie to ".foo.com"
    domainParts = host.split('.');
    domainParts.shift();
    domain = '.'+domainParts.join('.');

    document.cookie = name+"="+value+expires+"; path=/; domain="+domain;

    // check if cookie was successfuly set to the given domain
    // (otherwise it was a Top-Level Domain)
    if (getCookie(name) == null || getCookie(name) != value)
    {
      // append "." to current domain
      domain = '.'+host;
      document.cookie = name+"="+value+expires+"; path=/; domain="+domain;
    }
  }
}

export function getCookie(name) {
  var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)")
  if (arr = document.cookie.match(reg))
    return unescape(arr[2])
  else
    return null
}

export function delCookie(name) {
  var exp = new Date();
  exp.setTime(exp.getTime() - 1);
  var cval = getCookie(name);
  if (cval != null)
    document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}