关于Cookie、Session、Token以及后面的JWT 之间的关系对于初学者来说,肯定一下子理解不了,完全没关系;
因为: 随着技术迭代,实际开发中不同项目也有不同的处理方式,导致学起来本就很混乱:慢慢理解即可
什么是会话:
概述:会话是浏览器和服务器之间的多次请求↔响应: 很多情况通过HTTP进行 请求↔响应
HTTP 是一种无状态的协议,它没有记忆、没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户...
- A、B 同时登录
BiliBili📺
A喜欢看鬼畜👻、B喜欢看番剧🍅【都收藏了很多视频…】 - 但是,HTTP是无状态的每次请求都是一个新的开始,从而无法记录收藏记录🪶…
我们迫切的需要一种东西,可以用来判断用户状态,记录用户信息;
常见的会话控制技术有三种: Cookie🍪
、Session
、Token
Cookie🍪
Cookie 是什么: Cookie
是 HTTP服务器发送到用户浏览器,并保存在本地的一小块数据、按照域名划分保存;
是一种在客户端和服务器之间传递数据的机制,它最早出现于1994年
由 Netscape 公司的工程师 Lou Montulli 提出并实现
Cookie 运行流程: 浏览器向服务器发送请求时:需要进行记录,服务器通过response
向浏览器发送一个Cookie请求头
浏览器会把Cookie保存起来
,当浏览器再次访问服务器的时候,浏览器会把请求的网址及Cookie 一同提交给服务器
Cookie大小上限为4KB、一个服务器最多在客户端浏览器上保存20个Cookie、浏览器最多保存300个Cookie
面的数据是HTTP对Cookie的规范,但是现在一些浏览器可能会对Cookie规范 做了一些扩展
浏览器中的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 ID
、JavaScript 变量存储 Session 数据
、Session Storage
、Local 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毕业了伤心~