Token与Cookie、Session登录机制

news2024/10/5 23:37:45

Cookie

背景

Web 的兴起(所谓交互式就是你不光可以浏览,还可以登录,发评论,购物等用户操作的行为),单纯地浏览 web 已经无法满足人们的要求,比如随着网上购物的兴起,需要记录用户的购物车记录,就需要有一个机制记录每个连接的关系,这样我们就知道加入购物车的商品到底属于谁了,于是 Cookie 就诞生了。


机制

在这里插入图片描述


举例

以加入购物车为例,每次浏览器请求后 server 都会将本次商品 id 存储在 Cookie 中返回给客户端,客户端会将 Cookie 保存在本地,下一次再将上次保存在本地的 Cookie 传给 server 就行了,这样每个 Cookie 都保存着用户的商品 id,购买记录也就不会丢失了
在这里插入图片描述


缺点

随着购物车内的商品越来越多,每次请求的 cookie 也越来越大,这对每个请求来说是一个很大的负担,我只是想将一个商品加入购买车,为何要将历史的商品记录也一起返回给 server ?购物车信息其实已经记录在 server 了,浏览器这样的操作多此一举,改进方式如下


Cookie + Session

机制

由于用户的购物车信息都会保存在 Server 中,所以在 Cookie 里只要保存能识别用户身份的信息,知道是谁发起了加入购物车操作即可,这样每次请求后只要在 Cookie 里带上用户的身份信息,请求体里也只要带上本次加入购物车的商品 id,大大减少了 cookie 的体积大小,我们把这种能识别哪个请求由哪个用户发起的机制称为 Session(会话机制),生成的能识别用户身份信息的字符串称为 sessionId
在这里插入图片描述

  1. 首先用户登录,server 会为用户生成一个 session,为其分配唯一的 sessionId,这个 sessionId 是与某个用户绑定的,也就是说根据此 sessionid(假设为 abc) 可以查询到它到底是哪个用户,然后将此 sessionid 通过 cookie 传给浏览器
  2. 之后浏览器的每次添加购物车请求中只要在 cookie 里带上 sessionId=abc 这一个键值对即可,server 根据 sessionId 找到它对应的用户后,把传过来的商品 id 保存到 server 中对应用户的购物车即可

这种方式再也不需要在 cookie 里传所有的购物车的商品 id 了,大大减轻了请求的负担。注意, cookie 是存储在 client 的,而 session 保存在 server,sessionId 需要借助 cookie 的传递才有意义


痛点

上述情况能正常工作是因为我们假设 server 是单机工作的,假如集群部署则会出现问题。假设登录请求打到了 A 机器,A 机器生成了 session 并在 cookie 里添加 sessionId 返回给了浏览器,那么问题来了:下次添加购物车时如果请求打到了 B 或者 C,由于 session 是在 A 机器生成的,此时的 B,C 是找不到 session 的,那么就会发生无法添加购物车的错误,就得重新登录了
在这里插入图片描述


痛点解决办法

  1. session 复制: A 生成 session 后复制到 B, C,这样每台机器都有一份 session,无论添加购物车的请求打到哪台机器,由于 session 都能找到,缺点就是session 保存了多份,数据冗余
  2. session 粘连: 这种方式是让每个客户端请求只打到固定的一台机器上,比如浏览器登录请求打到 A 机器后,后续所有的添加购物车请求也都打到 A 机器上,Nginx 的 sticky 模块可以支持这种方式,支持按 ip 或 cookie 粘连,每个 client 请求到达 Nginx 后,只要它的 ip 不变,根据 ip hash 算出来的值会打到固定的机器上,也就不存在 session 找不到的问题了,缺点就是只要某一台机器宕机则处理不了对应的请求
upstream tomcats {   ip_hash;   server 10.1.1.107:88;   server 10.1.1.132:80; }

在这里插入图片描述

  1. session 共享: 主流方案,将 session 保存在 redis,memcached 等中间件中,请求到来时,各个机器去这些中间件取一下 session 即可,缺点就是每个请求都要去 redis 取一下 session,多了一次内部连接,消耗了一点性能,另外为了保证 redis 的高可用,必须做集群
    在这里插入图片描述

Token:no session!

机制

首先请求方输入自己的用户名,密码,然后 server 据此生成 token,客户端拿到 token 后会保存到本地,之后向 server 请求时在请求头带上此 token 即可。
在这里插入图片描述


原理

1、 token 只存储在浏览器中,服务端却没有存储,这样的话我随便搞个 token 传给 server 也行?

答:server 会有一套校验机制,校验这个 token 是否合法。

2、怎么不像 session 那样根据 sessionId 找到 userid 呢,这样的话怎么知道是哪个用户?

答:token 本身携带 userid 信息

在这里插入图片描述
token 主要由三部分组成

header:指定了签名算法

payload:可以指定用户 id,过期时间等非敏感数据

Signature: 签名,server 根据 header 知道它该用哪种签名算法,再用密钥根据此签名算法对 head + payload 生成签名,这样一个 token 就生成了。

当 server 收到浏览器传过来的 token 时,它会首先取出 token 中的 header + payload,根据密钥生成签名,然后再与 token 中的签名比对,如果成功则说明签名是合法的,即 token 是合法的。而且你会发现 payload 中存有我们的 userId,所以拿到 token 后直接在 payload 中就可获取 userid,避免了像 session 那样要从 redis 去取的开销。只要 server 保证密钥不泄露,那么生成的 token 就是安全的,因为如果伪造 token 的话在签名验证环节是无法通过的,就此即可判定 token 非法。


注意

token 一旦由 server 生成,它就是有效的,直到过期,无法让 token 失效,除非在 server 为 token 设立一个黑名单,在校验 token 前先过一遍此黑名单,如果在黑名单里则此 token 失效,但一旦这样做的话,那就意味着黑名单就必须保存在 server,这又回到了 session 的模式,那直接用 session 不香吗。所以一般的做法是当客户端登出要让 token 失效时,直接在本地移除 token 即可,下次登录重新生成 token 就好。 token 一般是放在 header 的 Authorization 自定义头里,不是放在 Cookie 里的,这主要是为了解决跨域不能共享 Cookie 的问题


与Cookie对比
1、 Cookie 跨站是不能共享的,这样的话如果你要实现多应用(多系统)的单点登录(SSO),使用 Cookie 来做需要的话就很困难了(要用比较复杂的 trick 来实现)
但如果用 token 来实现 SSO 会非常简单
在这里插入图片描述
只要在 header 中的 authorize 字段(或其他自定义)加上 token 即可完成所有跨域站点的认证。

2、 在移动端原生请求是没有 cookie 之说的,而 sessionid 依赖于 cookie,sessionid 就不能用 cookie 来传了,如果用 token 的话,由于它是随着 header 的 authoriize 传过来的,也就不存在此问题,换句话说token 天生支持移动平台,可扩展性好

综上所述,token 具有存储实现简单,扩展性好这些特点。


缺点

1、 token 太长了

token 是 header, payload 编码后的样式,所以一般要比 sessionId 长很多,很有可能超出 cookie 的大小限制(cookie 一般有大小限制的,如 4kb),如果你在 token 中存储的信息越长,那么 token 本身也会越长,这样的话由于你每次请求都会带上 token,对请求来是个不小的负担

2、 不太安全

我们说 token 是存在浏览器的,存在浏览器的哪里?既然它太长放在 cookie 里可能导致 cookie 超限,那就只好放在 local storage 里,这样会造成安全隐患,因为 local storage 这类的本地存储是可以被 JS 直接读取的,另外由上文也提到,token 一旦生成无法让其失效,必须等到其过期才行,这样的话如果服务端检测到了一个安全威胁,也无法使相关的 token 失效。

所以 token 更适合一次性的命令认证,设置一个比较短的有效期

不管是 cookie 还是 token,从存储角度来看其实都不安全,都有暴露的风险,我们所说的安全更多的是强调传输中的安全,可以用 HTTPS 协议来传输, 这样的话请求头都能被加密,也就保证了传输中的安全。


总结

session 和 token 本质上是没有区别的,都是对用户身份的认证机制,只是他们实现的校验机制不一样而已(一个保存在 server,通过在 redis 等中间件获取来校验,一个保存在 client,通过签名校验的方式来校验),多数场景上使用 session 会更合理,但如果在单点登录,一次性命令认证上使用 token 会更合适,最好在不同的业务场景中合理选型,才能达到事半功倍的效果。

详细跳转

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/827381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

寻找丢失数字:数学与位运算的解密之旅

本篇博客会讲解力扣“268. 丢失的数字”的解题思路,这是题目链接。 注意进阶中的描述:你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?这里我会讲解两种思路,它们的时间复杂度是O(N),空间复杂度是O(1)…

STM32F1基于标准库ST7735 1.8‘‘LCD显示DHT11数据

STM32基于标准库ST7735 1.8‘’LCD显示DHT11数据 📍HAL库驱动可以参考:《STM32基于HAL工程读取DHT11数据》🌼显示效果: 🌻ST7735 128x160 1.8’LCD屏幕 📌屏幕资料和相关驱动可以参考《1.8寸TFT LCD128…

JDK各版本重要变革

各版本更新详情 JDK8(LTS)--2014/3 语法层面 lambda表达式(重要特色之一) 一种特殊的匿名内部类,语法更加简洁允许把函数作为一个方法的参数,将代码象数据一样传递&#xff0c;即将函数作为方法参数传递基本语法: <函数式接口> <变量名> (参数...) -> { 方法…

迷你主机中的战斗机 Intel NUC 12 Serpent Canyon拆解

千呼万唤始出来&#xff0c;新一代游戏和创作者性能怪兽 mini主机 NUC 12 Serpent Canyon&#xff08;巨蛇峡谷终于发售了&#xff0c;以超紧凑的 2.5 升尺寸提供用户所需的所有性能和创新功能。NUC 12 Enthusiast 还首次将 Intel Deep Link 引入桌面&#xff0c;使 CPU 和 GPU…

类的继承和super关键字的使用(JAVA)

继承 所有的OOP语言都会有三个特征&#xff1a; 封装&#xff08;点击可跳转&#xff09;&#xff1b;继承&#xff1b;多态 为什么会有继承呢&#xff1f;可以先看下面的例子&#xff1a; 上面这两个类中的代码很相似因为它们只有最后一个方法不同其它的都相同&#xff0c;这样…

DbVisualizer Pro Crack

DbVisualizer Pro Crack DbVisualizer是适用于开发人员、DBA和分析师的通用数据库工具。它是最终的解决方案&#xff0c;因为相同的工具可以在访问各种数据库的所有主要操作系统上使用。支持的数据库Amazon Redshift、DB2 LUW、Exasol、H2、Informix、JavaDB/Derby、Microsoft …

【项目 进程10】2.21 alarm函数 2.22setitimer定时器函数

2.21 alarm函数 #include <unistd.h> unsigned int alarm(unsigned int seconds);功能&#xff1a;设置定时器&#xff08;闹钟&#xff09;。函数调用&#xff0c;开始倒计时&#xff0c;当倒计时为0的时候&#xff0c; 函数会给当前的进程发送一个信号&#xff1a;SIG…

C++中内存的动态管理

我们在C语言中了解到可以在栈区动态开辟空间&#xff0c;并且用完要进行释放&#xff0c;防止内存泄漏。 引入 C中也有可以进行动态开辟空间和释放空间的操作符new 、delete&#xff0c;虽然C中也可以用malloc、calloc、realloc、free函数&#xff0c;但是C中引入了类&#x…

宋浩概率论笔记(二)随机变量

本章节内容较多&#xff0c;是概率论与数理统计中最为重要的章节&#xff0c;对于概率密度和分布函数的理解与计算要牢牢掌握&#xff0c;才能在后期的学习中更得心应手。

小研究 - 微服务系统服务依赖发现技术综述(一)

微服务架构得到了广泛的部署与应用, 提升了软件系统开发的效率, 降低了系统更新与维护的成本, 提高了系统的可扩展性. 但微服务变更频繁、异构融合等特点使得微服务故障频发、其故障传播快且影响大, 同时微服务间复杂的调用依赖关系或逻辑依赖关系又使得其故障难以被及时、准确…

【Azure上云项目实战】 合规性的身份验证与访问控制:在 Azure 中实现符合 PCI DSS 要求的架构设计

文章目录 一、开篇写在前面二、项目背景及介绍三、Azure PCI DSS 项目架构及组件四、身份验证、访问控制4.1 三层防御控制4.2 三层部署结构 五、跳板机六、与 PCI DSS 要求的关系七、该篇总结&#xff08;重要&#xff09;写在文末 一、开篇写在前面 各位博客阅读者们以及对云…

【A200】Ubuntu18.04 + ROS-Melodic + 比业电子VISIOSCAN雷达 评测

大家好&#xff0c;我是虎哥&#xff0c;朋友介绍&#xff0c;有一款单线激光雷达&#xff0c;25米的检测距离&#xff0c;有80HZ的扫描频率&#xff0c;而且角度分辨率最高可以到0.1&#xff0c;这个参数我确实没有见过&#xff0c;所以立刻着手从厂家那申请到了VISIOSCAN雷达…

Android的Handler消息通信详解

目录 背景 1. Handler基本使用 2. Handler的Looper源码分析 3. Handler的Message以及消息池、MessageQueue 4. Handler的Native实现 4.1 MessageQueue 4.2 Native结构体和类 4.2.1 Message结构体 4.2.2 消息处理类 4.2.3 回调类 4.2.5 ALooper类 5. 总结&…

轻量级目标检测模型NanoDet-Plus微调、部署(保姆级教学)

前言 NanoDet-Plus是超快速、高精度的轻量级无锚物体检测模型&#xff0c;github项目文件。可以在移动设备上实时检测。其主要特点是 超轻量&#xff1a;模型文件仅980KB(INT8)、1.8MB(FP16)超快&#xff1a;移动ARM CPU上97fps&#xff08;10.23ms&#xff09;高精度&#xf…

C++内存管理(动态内存开辟)

我们在C语言当中想要使用堆区的空间的时候就需要使用malloc函数进行手动的申请&#xff0c;但是我们在申请的时候需要手动进行计算&#xff0c;经过计算之后还需要进行判空操作&#xff0c;并且还不能进行任意值的初始化。这一切看起来在学习完C当中的动态开辟之前显得很正常&a…

最新版本mac版Idea 激活Jerbel实现热部署

1.环境准备 1.安装docker desktop 客户端创建本地服务 2.创建guid 3.随便准备一个正确格式的邮箱 2.具体操作 1.通过提供的镜像直接搭建本地服务 docker pull qierkang/golang-reverseproxy docker run -d -p 8888:8888 qierkang/golang-reverseproxy2.guid 通过如下网址直…

小C说历史(人物介绍第一篇):传奇人物Linus Torvalds 缔造Linux和Git

传奇人物Linus Torvalds 缔造Linux和Git Linus Torvalds&#xff0c;1969年12月28日出生于芬兰的赫尔辛基&#xff0c;Linux核心的创作者。当Linus十岁时&#xff0c;他的祖父&#xff0c;赫尔辛基大学的一位统计教授&#xff0c;购买了一台Commodore VIC-20计算机。Linus帮助他…

Mybatis-Plus面向实用知识点——结合SpringBoot

目录 环境配置基本流程各类中的方法BaseMapperIServiceCOUNTGETQueryListPageRemoveSaveUpdate 环境配置 参考java项目各框架环境配置 基本流程 创建Mapper Mapper public interface MyMapper extends BaseMapper<Entity>{}创建Service public interface MyService …

【娱乐圈明星知识图谱2】信息抽取

目录 1. 项目介绍 2. 信息抽取介绍 3. ChatGPT 信息抽取代码实战 4. 信息抽取主逻辑 5. 项目源码 1. 项目介绍 利用爬虫项目中爬取的大量信息 【娱乐圈明星知识图谱1】百科爬虫_Encarta1993的博客-CSDN博客娱乐圈明星知识图谱百度百科爬虫百度百科爬虫百度百科爬虫百度百…

【vue】 vue2 监听滚动条滚动事件

代码 直接上代码&#xff0c;vue单文件 index.vue <template><div class"content" scroll"onScroll"><p>内容</p><p>内容</p><p>内容</p><p>内容</p><p>内容</p><p>内容…