session、cookie、token

cookie

cookie 是一种在客户端存储数据的技术,它是由服务器发送给客户端的小型文本文件,用来记录用户的一些信息,存储在客户端的浏览器中,大小限制大致在 4KB 左右。

cookie 主要用于以下三个方面:

  1. 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  2. 个性化设置(如用户自定义设置、主题等)
  3. 浏览器行为跟踪(如跟踪分析用户行为等)

cookie 主要特点:

  1. cookie 存储在客户端
  2. cookie 不可跨域,但是在如果设置了 domain,那么它们是可以在一级域名和二级域名之间共享的

cookie虽然可以用来存储各种数据,但随着更多浏览器存储方案的出现,cookie存储数据这种方式逐渐被取代,主要原因有如下:

  1. cookie 有存储大小限制,4KB 左右
  2. 浏览器每次请求会携带cookie在请求头中
  3. 字符编码为 Unicode,不支持直接存储中文
  4. 数据可以被轻易查看

cookie的主要属性

属性名 描述
name cookie 的名称
value cookie 的值
comment cookie 的描述信息
domain 可以访问该 cookie 的域名
expires cookie 的过期时间,具体某一时间
maxAge cookie 的过期时间
path cookie 的使用路径
secure cookie 是否使用安全协议传输,比如 SSL 等
version cookie 使用的版本号
isHttpOnly 指定该 cookie 无法通过 JavaScript 脚本拿到,比如 Document.cookie 属性、XMLHttpRequest 对象和 Request API 都拿不到该属性。这样就防止了该 cookie 被脚本读到,只有浏览器发出 HTTP 请求时,才会带上该 cookie

流程

客户端向服务端发送请求时,服务端需要记录该用户的状态和一些信息,服务端就会设置响应头的Set-Cookie字段信息来通知客户端保存cookie。当客户端再向服务端发起请求时,客户端会自动在请求头中将相应的cookie信息发送给服务端,服务端接通过读取客户端发送过来的cookie信息,就可以判断是来自哪个客户端发送过来的请求,以此来辨认用户状态。

第一次客户端发起请求服务端返回的响应信息如下:响应头Response HeadersSet-Cookie的字段信息来通知客户端保存Cookie。

当客户端再次发送请求到服务端时,就携带了cookie信息在请求头Request Headers中一同发送给了服务端:

通过 cookie 来实现用户确定或者权限确定流程图如下:

  1. 客户端发送请求到服务端(比如登录请求)
  2. 服务端收到请求后生成一个 session 会话
  3. 服务端响应客户端,并在响应头中设置Set-Cookie字段。Set-Cookie字段里面包含了 sessionId,它的格式如下:Set-Cookie: value; expires=date;domain=domain;path=path;secure。其中 sessionId就是用来标识客户端的
  4. 客户端收到该请求后,如果服务端响应头设置了Set-Cookie字段,那么客户端发送其它请求就会在请求头中自动携带 cookie,cookie 中携带有用户信息等
  5. 服务端接收到请求,验证 cookie 信息,比如通过 sessionId 来判断是否存在会话,存在则正常响应

session

session在网络应用中称为会话控制,是服务器为了保存用户状态而创建的一个特殊的对象。session就是一个存储于服务器端的对象,用于存储信息

服务器会为每一个浏览器(客户端)创建一个唯一的session,这个session是服务器端共享,每个浏览器(客户端)独享。可以在session对象中存储数据,实现数据共享。

session的存储形式

session类似于一个Map字典,里面可以存放多个键值对,是以key-value键值对的形式进行存放的。key必须是一个字符串,value是一个对象。

session底层实现机制

session是每一个浏览器(客户端)所唯一的,其实现机制是:HTTP请求的请求头中可以携带cookie,这个cookie包含了sessionId,这个sessionId表示的就是session所对应的sessionId,这个是由服务端创建的,并且是唯一的。服务端在使用session时,会根据sessionId来进行不同操作。

  1. 客户端(浏览器)发送首次请求到服务端
  2. 服务端收到请求,发现客户端没有提供会话ID(缺少一个值为 sessionId 的cookie)
  3. 服务端创建一个新的会话,生成一个唯一的会话ID,并将创建的 sessionId 存储在cookie 中返回给客户端,以及将会话数据保存在服务端存储的session对象中(可以将session对象存储在内存、数据库等)
  4. 服务端将会话ID放在响应头的 Set-Cookie 字段中发送回客户端,客户端浏览器会存储这个会话ID。
  5. 自此,客户端的每个请求都会附带这个会话ID的 sessionId cookie。
  6. 服务器根据收到的会话ID,从服务端的存储中查找相应的会话数据,以恢复用户的会话状态

通常情况下,cookie 和 session 都是结合着来用,服务器端将 session 的唯一标识 sessionId 通过设置响应头Set-Cookie 的方式响应给客户端,客户端将 sessionId 存到 cookie 中。当然可以单独只使用 cookie 或者单独只使用 session,这里将 cookie 和 session 结合着来用,如下图:

使用express框架管理session(会话)

需要使用express-session中间件,可以使用下面的命令安装这个模块:

ssh 复制代码
npm i express-session

举例:使用session记录页面访问次数

js 复制代码
import express from 'express';
import session from 'express-session';
// 引入中间件
import loggerMiddleware from './middleware/logger.js'
// express是函数
const app = express();
// 注册中间件,需要在注册路由模块前先执行,否则路由请求不会经过该中间件
app.use(loggerMiddleware);
// 使用express-session中间件
app.use(session({
    secret:'secret_Key', // 密钥,用来签名sessionId
    name: "sessionName", // 修改session对应的cookie的名称
    resave:false, // 会话在请求过程中未被修改过就不保存
    saveUninitialized: false, // 未初始化的session不存储
}));
// 中间件初始化静态资源,传入静态资源目录名,如此该目录下的文件就会作为静态资源
// 访问资源时加上前缀
app.use('/assets',express.static('static'));
app.get('/',(req,res) => {
    if(req.session.views){
        // req.session的views属性存在,表示views的session对象存在
        req.session.views++;
        res.json({
            code:200,
            data:`第${req.session.views}次访问页面`
        });
    }else {
        // req.session的views属性不存在,第一次访问页面,访问页面次数为1
        req.session.views = 1;
        res.json({
            code:200,
            data:`第一次访问页面`
        });
    }
});
app.listen(8089, () => {
    console.log("8089端口已启动");
});

当客户端第一次请求时,服务端给req.session写入一个views属性并在响应头返回保存了该属性的session对象的cookie给客户端。当客户端再次发起请求时会在请求头携带保存了sessionId的cookie给服务端,服务端把req.session.views加1,然后返回给客户端。客户端再次请求之后会响应用户访问的次数。

session与cookie的区别

cookie 和 session,它们两者之间主要是通过 sessionId 关联起来的,所以sessionId 是 cookie 和 session 之间的桥梁。

  1. 作用范围不同:cookie 保存在客户端(浏览器),session 保存在服务端。
  2. 存取方式不同:cookie 保存中文属于Unicode字符,在内存中占4个字节,而英文属于ASCII字符,内存中只占2个字节。cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会乱码。因此cookie中保存中文只能编码,一般使用UTF-8编码即可。session 可以存任意数据类型。
  3. 隐私策略不同:cookie 存储在客户端且是明文显示,比较容易导致信息被窃取。session 存储在服务端,安全性相对 cookie 要好一些。
  4. 存储大小不同:session 存储空间很大,cookie 有限制。

系统想要实现鉴权,可以单独使用 cookie,也可以单独使用 session,但是建议结合两者使用。

token

token 是一种在客户端和服务端之间传递身份信息的方式。当用户登录成功后,服务端会生成一个 token,将其发送给客户端。客户端在后续的请求中,需要将 token 携带在请求头或请求参数中。服务端通过验证 token 的合法性,就可以确定该请求来自哪个用户,并且可以根据用户的权限进行相应的操作。token 可以有效地避免了cookie 的一些安全问题,比如 CSRF 攻击。

token的组成

token是一个由一串字符组成的令牌,用于在计算机系统中进行身份验证和授权。它通常由三个部分组成:标头、有效载荷、签名。

  1. 标头(Header):包含了算法和类型,用于指定如何对有效载荷进行编码和签名。常用的算法有HMAC、RSA、SHA等。
  2. 有效载荷(Payload):包含了一些信息,如用户ID、角色、权限等,用于验证身份和授权。有效载荷可以是加密的,也可以是明文的。
  3. 签名(Signature):是对标头和有效载荷进行签名后得到的值,用于验证token的完整性和真实性。签名通常使用私钥进行签名,并使用公钥进行验证。

一个完整的token包含了标头、有效载荷和签名三个部分,它们一起构成了一个安全的令牌,用于进行身份验证和授权。

token认证流程

  1. 客户端发起登录请求,比如用户输入用户名和密码后登录。
  2. 服务端校验用户名和密码后,将用户 id 和一些其它信息进行加密,生成 token
  3. 服务端将 token 响应给客户端
  4. 客户端收到响应后将 token 存储下来
  5. 下一次发送请求后需要将 token 携带上,比如放在请求头中或者请求体中
  6. 服务端 token 后校验,校验通过则正常返回数据

session、cookie、token对比

cookie、session、token三者最终的目的都是一样:鉴权和认证

方式 特点 优点 缺点
cookie 1.存储在客户端;2.请求自动携带 cookie;3.存储大小 4KB。 1.兼容性好;2.容易实现,因为 cookie 会自动携带和存储。 1.需要单独解决跨域携带问题,比如多台服务器如何共享 cookie;2.会遭受 CSRF 攻击;3.存储在客户端,不够安全。
session 1.存储在服务端;2.存储大小无限制。 1.查询速度快,因为是个会话,相当于是在内存中操作;2.结合 cookie 后很容易实现鉴权;3.安全,因为存储在服务端。 1.耗费服务器资源,因为每个客户端都会创建 session;2.占据存储空间,session 相当于存储了一个完整的用户信息。
token 1.体积很小;2.自由操作存储在哪里 1.安全,因为 token 一般只有用户 id,就算被截取了也没什么用;2.无需消耗服务器内存资源,它相当于只存了用户 id,session 相当于存储了用户的所有信息;3.跨域处理较为方便,比如多台服务器之间可以共用一个 token。 查询速度慢,因为 token 只存了用户 id,每次需要去查询数据库。(可以使用redis缓存中间件,不必频查数据库,查询一次后缓存使用)
相关推荐
浮华似水22 分钟前
简洁之道 - React Hook Form
前端
正小安2 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光4 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   4 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   4 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web4 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常4 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇5 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr5 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui