会话控制💬:

244 阅读5分钟

关于Cookie、Session、Token以及后面的JWT 之间的关系对于初学者来说,肯定一下子理解不了,完全没关系;

因为: 随着技术迭代,实际开发中不同项目也有不同的处理方式,导致学起来本就很混乱:慢慢理解即可

什么是会话:

概述:会话是浏览器和服务器之间的多次请求↔响应: 很多情况通过HTTP进行 请求↔响应

HTTP 是一种无状态的协议,它没有记忆、没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户...

  • A、B 同时登录BiliBili📺 A喜欢看鬼畜👻、B喜欢看番剧🍅【都收藏了很多视频…】
  • 但是,HTTP是无状态的每次请求都是一个新的开始,从而无法记录收藏记录🪶…

我们迫切的需要一种东西,可以用来判断用户状态,记录用户信息;

常见的会话控制技术有三种: Cookie🍪SessionToken

Cookie🍪

Cookie 是什么: Cookie是 HTTP服务器发送到用户浏览器,并保存在本地的一小块数据、按照域名划分保存;

是一种在客户端和服务器之间传递数据的机制,它最早出现于1994年由 Netscape 公司的工程师 Lou Montulli 提出并实现

Cookie 运行流程: 浏览器向服务器发送请求时:需要进行记录,服务器通过response向浏览器发送一个Cookie请求头

浏览器会把Cookie保存起来,当浏览器再次访问服务器的时候,浏览器会把请求的网址及Cookie 一同提交给服务器

Cookie大小上限为4KB、一个服务器最多在客户端浏览器上保存20个Cookie、浏览器最多保存300个Cookie

面的数据是HTTP对Cookie的规范,但是现在一些浏览器可能会对Cookie规范 做了一些扩展

image-20240426230607182.png

浏览器中的Cookie设置: 生活中经常使用浏览器,应该总会看到Cookie的标识,此处应该有所了解了吧!!

Cookie 本质是存储在浏览器本地的,所以要注意管理,经常使用的记住密码就是Cookie的功能!!

浏览器也可以通过设置进行:禁用🚫、删除🗑️、查看🔎 可能会影响部分网站的使用

对于早期Cookie会存在安全隐患,现在大型网站都会进行加密㊙️,不用太担心💔

同一设备不同浏览器的Cookie是不会共享的

Express设置Cookie

此处通过,Node+Express进行测试模拟:会话控制,但不要固定思维🧠,会话属于Web领域的技术概念;

任何的编程语言都可以对其进行实现,可能方式不同罢了,代码也不需要强制记忆,了解规律即可~

🥷初学者,此时一定很吃力也不必强迫症搞明白,很多框架都二次封装多很多概念🗐

 //为了方便操作此处使用Npm中一个Cookie工具包: npm i cookie-parser
 const cookieParser = require('cookie-parser')
 const express = require('express');
 //定义应用对象,并设置中间件;
 const app = express();
 app.use(cookieParser());
 ​
 /**为了方便演示此处并没有加密: */
 //服务器C端设置Cookie
 //方式一: res.cookie(key,value);        会在浏览器关闭的时候, 销毁
 //方式二: res.cookie(key,value,毫秒);   定义k,v 同时{maxAge: xxx} 设置Cookie最大过期时间;
 //...实际开发中还有更多设置: Cookie不可读、不可写之类的控制,都是为了保证安全;
 app.get('/setCookie', (req, res) => {
     res.cookie('name1', 'zhangsan');                 // 会在浏览器关闭的时候销毁
     res.cookie('name2','lisi', {maxAge: 60 * 1000})  // 设置Cookie最大过期时间,同名Cookie Key后来者居上会进行覆盖;
     res.send('成功!! 设置cookie');
 });
 ​
 //服务器C端查询Cookie
 //🆗 成功设置了Cookie之后的任何一个请求都会携带这个Cookie进行请求了
 app.get('/getCookie', (req, res) => {
     console.log(req.cookies);                       //通过中间件进行过滤cookie则可以直接使用了;
     res.send(`欢迎您 ${req.cookies}`);
 })
 ​
 //服务器C端删除Cookie
 app.get('/removeCookie', (req, res) => {
     res.clearCookie('name');                        //删除指定的Key
     res.send('删除成功~~');
 });
 ​
 //启动服务
 app.listen(5400);

上述我们通过Node+Express完成了,简单的Cookie设置: 实际工作中常用场景 登录

  • 😊用户A 在自己的电脑通过浏览器🪟,注册登录网站🗔
  • 网站🗔 —HTTP请求—服务器🗄️,服务器内经过处理验证… 登录|注册成功!
  • 返回响应:set-cookie:用户=信息浏览器🪟 Cookie🍪浏览器🪟保存记录Cookie🍪
  • 并在之后的每一次请求都会携带这个Cookie🍪,服务器可以获取Cookie,由此区分用户,实现持久会话机制;

😐用户B、C... 也有自己的电脑浏览器,每个人都有自己的Cookie,使服务器可以区分不同的用户,进行不同的内容展示;

Session

随着时间的推移,Cookie的很多缺点也出现了: 安全型、存储容量、生命周期

Session 由此诞生: 和Cookie一样也是为了解决优化:HTTP的无状态协议特性,实现持久会话;

和Cookie 不同: Session 是一种在服务端存储数据的技术,由服务端生成控制更安全、生命周期可控;

安全性:

  • Cookie 存储在客户端,容易被篡改,且信息存储在文本文件中,任何人都可以查看
  • Session 存储在服务端,相对更安全,通常数据以二进制或加密形式保存,只能在服务器上解码

存储容量:

  • Cookie 的最大容量为 4KB,无法存储大量用户信息
  • Session 可以存储更多数据,没有容量限制,但有一定的内存限制:也有部分的解决措施

生命周期:

  • Cookie 的生命周期由用户设置,当用户退出浏览器或注销登录时,Cookie 结束
  • Session 的生命周期由服务器控制,可以持续一段时间,直到用户主动注销或关闭浏览器

扩展Tips🔖: Session很多情况下,依赖于Cookie使用弥补Cookie的缺点,Cookie 不依赖于 Session,可以独立使用;

  • Cookie+Session 实现会话登录:

    😊用户A 在自己的电脑通过浏览器🪟,注册登录网站🗔

    网站🗔 —HTTP请求—服务器🗄️,服务器内经过处理验证… 登录|注册成功!

    服务器内将用户信息、某些数据通过,服务器内的加密算法进行加密,并生成一个Session🆔

    返回响应:set-cookie:SessionId=???浏览器🪟 Cookie🍪浏览器🪟保存记录Cookie🍪

    并在之后的每一次请求都会携带这个Cookie🍪,服务器通过Cookie获取Session,由此区分用户,实现持久会话

    优点:客户端仅存储了加密🔒的Session🆔保证了数据安全,节省了Cookie的容量小问题,服务器端控制生命周期

  • Session+Redis扩容优化:

    随着技术成熟:前后端分离、后端压力过大,很多大型项目 📺前端——>对应多个服务端🖧

    Session 由某一服务进行生成,仅存放在生成服务器的内存中,那个如何在多个服务端之间共享呢?当然有多种解决方案:

    • 一: 通过特定的规则算法,在请求过程中,发送到对应的服务模块,但显然比较麻烦,影响程序效率;

    • 二: Redis 作为中间服务器,所有的Session都放在里面,大家一起去存|取,几乎完美解决了!

      且解决了Session过多,内存不足的情况,Redis可以随时进行扩充;

  • Session除了Cookie其他实现方式:

    URL 中传递 Session IDJavaScript 变量存储 Session 数据Session StorageLocal Storage

总之,Session 解决了 Cookie 在安全性、存储容量和生命周期等方面的局限性,提供了更好的用户状态管理和数据存储方式

 //导入 express
 const express = require('express');
 //引入 npm i express-session  connect-mongo
 const session = require("express-session");     //NPM包 封装了对Session的设置操作
 // const MongoStore = require('connect-mongo');    //NPM包 将Sessio存储在MongoDB数据库中
 ​
 //创建应用对象
 const app = express();
 //设置 Session 的中间件
 app.use(session({
   name: 'sid',                  //设置cookie的name 默认: sid
   secret: 'atguigu',            //参与加密的字符串(又称签名\加盐: 确保Session加密安全  
   saveUninitialized: false,     //是否为每次请求都设置一个cookie用来存储session的id,一般仅第一个请求如此
   resave: true,                 //是否在每次请求时重新保存session 只要还在使用Session就不会过期
 //   store: MongoStore.create({    //[可选] 数据库的连接配置,Session保存入Mongodb中,默认保存至内存
 //     mongoUrl: 'mongodb://127.0.0.1:27017/bilibili' 
 //   }
   cookie: {
     httpOnly: true,             //开启后前端无法通过 JS 操作此cookie: 确保安全性;
     maxAge: 1000 * 60 * 5       //控制 sessionID 的过期时间的!!!
   },
 }))
 ​
 //session 的设置: 中间件内已经完成封装直接使用即可;
 //假设登录: 用户名|密码:admin
 app.get('/login', (req, res) => {
   if(req.query.username === 'admin' && req.query.password === 'admin'){
     //登录成功设置 session 信息
     req.session.username = 'admin';
     req.session.uid = '258aefccc';
     res.send('登录成功');
   }else{
     res.send('登录失败~~');
   }
 })
 ​
 //session 的读取: 中间件内已经完成封装直接使用即可;
 app.get('/cart', (req, res) => {
   if(req.session.username){ res.send(`购物车页面, 欢迎您 ${req.session.username}`)
   }else{ res.send('您还没有登录~~'); }
 });
 ​
 //session 的销毁
 app.get('/logout', (req, res) => {
   req.session.destroy(() => { res.send('退出成功~~'); })
 })
 ​
 //启动服务
 app.listen(5400);
  • http://127.0.0.1:5400/login?username=admin&password=admin 首先登录,服务端生成Session 并响应Cookie中
  • http://127.0.0.1:5400/cart 前端通过浏览器查看Cookie:sid:xxx、服务端中间件之间获取Session中的数据;
  • 只要Cookie|Session不销毁,该浏览器对该网站的每一次请求都会携带Sid,服务端就可以获取对应用户消息📢
  • http://127.0.0.1:5400/logout 接口,服务端销毁Session 则服务端无法之间获取用户消息;

Token

Session 对于多服务端,前后端分离等情况并不适合

因为: SessionID 属于非长期、且高频数据,一般都是存储在内存中,大量Session存储服务器端压力过大😓

Token 和Session 有异曲同工之妙,都是由服务器生成: Token是:一串加密字符串🧬, Token 中保存着用户信息

  • 加密字符串: 通过某种算法将数据 加密成一段无规则字符串,并可以反编译回原始数据
  • 优点: 安全性更高:Token 无法被篡改,适用于前后端分离的应用;

Session 存储在服务端,相对安全,但有一定的内存限制,获取SessionID 查询到对应用户信息;

Token 存储在客户端,更灵活,适用于前后端分离的应用,前端请求头携带Token 反编译出用户信息;

JWT

JWTJSON Web Token 可以看作是 Token 的一种具体技术实现:

Token 是一个广义的术语,用来表示任何一种用于身份验证和授权的令牌

它可以指代各种类型的令牌,包括 JWT、OAuth 令牌等,💁很久以前写的一篇关于JWT的详细介绍:


我们可以使用 jsonwebtoken NPM包 来操作 Token: npm i jsonwebtoken

 //导入JWT
 const JWT = require('jsonwebtoken');
 ​
 //创建(生成) token 
 // let TokenStr = JWT.sign(加密用户数据, 加密字符串, 配置对象);
 let TokenStr = JWT.sign(
     {
         username: 'zhangsan',
         password: '123456wsm',
     }, 
     'wsm',                          //加密字符串,确保数据安全;
     { expiresIn: 60, }              //配置对象: 设置Token有效时间单位是秒
 );
 ​
 console.log(TokenStr);              //生成的Token
 ​
 //校验:                             //解析Token
 JWT.verify(TokenStr, 'wsm', (err, data) => {
   if(err){ return console.log('校验失败~~');  }
   console.log(data);                //返回解析后的数据信息;
 })

🆗:See you Next Time 终于写完了!!

最近喜欢的VUP毕业了伤心~

v2-8b0e99851d96ca71629a911efe998dd8_720w.jpg