乐趣区

大话javascript 7期:Cookie、Session和Token的那些事儿

一、登录认证机制
随着互联网的不断发展,无论是网站还是 app,一般都会要求用户注册 / 登录。主要的登录方式有账户密码登录、第三方登录(微信登录、QQ 登录、微博登录等)
登录可分为三个阶段(登录验证、登录持续、退出登录);登录验证指客户端提供账号 / 密码(或第三方平台(微信、qq)获取 openid/unionid)向服务器提出登录请求,服务器应答请求判断能否登录并返回相应数据;登录持续指客户端登录后,服务器能够分辨出已登录的客户端,并为其持续提供登录权限的服务器。退出登录指客户端退出登录状态。
二、保持登录持续状态的实现方式
为什么要保持登录状态的持续?
由于 HTTP 是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证
方案:客户端登录成功后,服务器为其分配一个唯一的凭证, 客户端每次请求资源时都带上这个凭证;
实现方案

cookie 会话机制
session 会话机制
token 会话机制

三、Cookie、Session 和 Token
Cookie(浏览器缓存)
1. 什么是 Cookie
Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用 response 向客户端浏览器颁发一个 Cookie。客户端浏览器会把 Cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容。

cookie 其实是补充 http 协议的无状态性的缺点,底层是通过服务器端在 http 响应消息中增加 set-cookie 字段来将 cookie 信息发送给浏览器端,因为它只能存 4k,一般用来存浏览器的身份信息,浏览器在访问服务器的某些资源的时候,会在 http 请求头中将 cookie 数据传给服务器,这样服务器就知道是谁请求的了,但是如果用户清除了 cookie,那就啥都没有了
2.Cookie 的属性

1、Expires: 该 Cookie 失效的时间,单位秒。

如果为正数,则该 Cookie 在 maxAge 秒之后失效 (持久级别 Cookie)。
如果为负数,该 Cookie 为临时 Cookie,关闭浏览器即失效 (会话级别 Cookie),浏览器也不会以任何形式保存该 Cookie。
如果为 0,表示删除该 Cookie。默认为–1;

2、Domain: 我们现在有二个域名。域名 A:b.f.com,域名 B:d.f.com;显然域名 A 和域名 B 都是 f.com 的子域名

如果我们在域名 A 中的 Cookie 的 domain 设置为.f.com,那么.f.com 及其子域名都可以获取这个 Cookie,即域名 A 和域名 B 都可以获取这个 Cookie
如果域名 A 没有显式设置 Cookie 的 domain 方法,那么 domain 就为.b.f.com,不一样的是,这时,域名 A 的子域名将无法获取这个 Cookie
HttpOnly: 这个属性是面试的时候常考的,如果这个属性设置为 true,就不能通过 js 脚本来获取 cookie 的值,能有效的防止 xss 攻击

3.Cookie 的操作
封装 cookie 的常用操作方法

设置 cookie
读取 cookie
删除 cookie

var cookieUtil = {
getItem: function (name) {
var cookieName = encodeURIComponent(name) + “=”,
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(‘;’, cookieStart);
if (cookieEnd == 1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd))
}
return cookieValue;
},
setItem: function (name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + “=” + encodeURIComponent(value);
if (expires) {
cookieText += “;expires=” + expires.toGMTString();
}
if (path) {
cookieText += “;path=” + path;
}
if (domain) {
cookieText += “;domain=” + domain;
}
if (secure) {
cookieText += “;secure”;
}
document.cookie = cookieText;
},
unset: function (name, path, domain, secure) {
this.setItem(name, “”, new Date(0), path, domain, secure)
}
}
CookieUtil.setItem(“name”, ‘tom’); // 设置 cookie
console.log(CookieUtil.getItem(‘name’));// 读取 cookie
CookieUtil.unset(“name”)// 删除 cookie

4.Cookie 防篡改机制
因为 Cookie 是存储在客户端,用户可以随意修改。所以,存在一定的安全隐患。防篡改签名:服务器为每个 Cookie 项生成签名。如果用户篡改 Cookie,则与签名无法对应上。以此,来判断数据是否被篡改。
原理如下:

服务端提供一个签名生成算法 secret
根据方法生成签名 secret(wall)=34Yult8i
将生成的签名放入对应的 Cookie 项 username=wall|34Yult8i。其中,内容和签名用 | 隔开。
服务端根据接收到的内容和签名,校验内容是否被篡改。

举个栗子:比如服务器接收到请求中的 Cookie 项 username=pony|34Yult8i,然后使用签名生成算法 secret(pony)=666。算法得到的签名 666 和请求中数据的签名不一致,则证明数据被篡改。
Session(会话)
1. 什么是 session
session 是一种服务器机制,是存储在服务器上的信息,主要配合 cookie 完成浏览器的身份认证和状态存储方式多种多样,可以是服务器的内存中,或者是 mongo 数据库,redis 内存数据库中。为了获得更高的存取速度,服务器一般把 Session 放在内存里。每个用户都会有一个独立的 Session。如果 Session 内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session 里的信息应该尽量精简。
Session 相对于 cookie 较安全点,当用户请求服务器的时候,服务器会把数据临时存下来,如果退出网站后,session 会被销毁。
Session 是基于 cookie 实现的,浏览器第一次访问服务器时,服务器创建一个 Session,同时生成一个唯一的会话 key,即 sessionID。接着 sessionID 及 session 分别作为 key 和 value 保存到缓存中,也可以保存到数据库中,然后服务器把 sessionID 通过 set-cookie 的方式写入浏览器,浏览器下次访问服务器时直接携带上 cookie 中的 sessionID,服务器再根据 sessionID 找到对应的 session 进行匹配,来判断用户是否登录
2.session 鉴权过程
【1】客户端发起登录请求,服务器端创建 session,并通过 set-cookie 将生成的 sessionID 写入的客户端的 cookie 中。【2】在发起其他需要权限的接口的时候,客户端的请求体的 Header 部分会携带 sessionID 发送给服务端。然后根据这个 sessionId 去找服务器端保存的该客户端的 session,然后判断该请求是否合法。
3.cookie 和 session 的区别

Token(身份令牌)
1. 什么是 token
token 的意思是“令牌”,是用户身份的验证方式,最简单的 token 组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由 token 的前几位 + 盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接 token 请求服务器)。还可以把不变的参数也放进 token,避免多次查库
浏览器第一次访问服务器,根据传过来的唯一标识 userId,服务端会通过一些算法,如常用的 HMAC-SHA256 算法,然后加一个密钥,生成一个 token,然后通过 BASE64 编码一下之后将这个 token 发送给客户端;客户端将 token 保存起来,下次请求时,带着 token,服务器收到请求后,然后会用相同的算法和密钥去验证 token,如果通过,执行业务操作,不通过,返回不通过信息;
2.token 生成方式
浏览器第一次访问服务器时,服务器根据传过来的唯一标识 userId,通过一些算法,加一个密钥,生成一个 token,接着通过 base64 编码将 token 返回给客户端。客户端将 token 保存起来,下次请求时需要带着 token,服务器收到请求后,用相同的算法和密钥去验证 token
3.token 和 session 的区别
token 和 session 其实都是为了身份验证,session 一般翻译为会话,而 token 更多的时候是翻译为令牌;session 服务器会保存一份,可能保存到缓存,文件,数据库;同样,session 和 token 都是有过期时间一说,都需要去管理过期时间;其实 token 与 session 的问题是一种时间与空间的博弈问题,session 是空间换时间,而 token 是时间换空间。两者的选择要看具体情况而定。虽然确实都是“客户端记录,每次访问携带”,但 token 很容易设计为自包含的,也就是说,后端不需要记录什么东西,每次一个无状态请求,每次解密验证,每次当场得出合法 / 非法的结论。这一切判断依据,除了固化在 CS 两端的一些逻辑之外,整个信息是自包含的。这才是真正的无状态。而 sessionid,一般都是一段随机字符串,需要到后端去检索 id 的有效性。万一服务器重启导致内存里的 session 没了呢?万一 redis 服务器挂了呢?
sessionID 是基于 cookie 实现的,而 token 不需要基于 cookie。这就导致了 sessionID 只能用在浏览器上,对于原生的应用无法实现。原生的应用是不具备 cookie 的特性的。另外 sessionID 可以实现服务端注销会话,而 token 不能 (当然你可以把用户登陆的 token 存入到 redis 中,但是不推荐 token 入库)
4.token 的优点
Token 作为用户认证的处理方式,有几个优点:

无状态,可扩展:不会在服务端存储用户的登录状态,可以很容易的实现服务器的增减
支持移动设备,对多类型客户端的支持良好
支持跨程序调用,各个接口之间的调用更方便
安全可靠

5. 什么是 JSON Web Token
JSON web Token, 简称 JWT,本质是一个 token,是一种紧凑的 URL 安全方法,用于在网络通信的双方之间传递。一般放在 HTTP 的 headers 参数里面的 authorization 里面,值的前面加 Bearer 关键字和空格。除此之外,也可以在 url 和 request body 中传递。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519). 该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。
如果你觉得这篇文章对你有所帮助,那就顺便点个赞吧,点点关注不迷路~
黑芝麻哇,白芝麻发,黑芝麻白芝麻哇发哈!
前端哇发哈

退出移动版