cookie、session和Token的区别?JWT又是什么?单点登录又是什么?头大?快进来看看,一文帮你捋清楚~

news2024/11/24 13:46:12

目录

0、HTTP是无状态的

1、前端标记cookie

1.1、cookie限制空间范围

1.2、cookie限制时间范围

1.3、cookie限制使用方式

2、服务端存储session库

2.1、我们先来简单聊聊session是什么?

2.2、session的存储方式

2.3、session的过期和销毁

2.4、session的分布式问题

2.5、session的缺点

3、token

3.1、理解token 

3.2、客户端存储token

3.3、token过期

3.4、token的编码

4、JWT

4.1、简单介绍JWT

4.2、JWT的组成

4.2.1、JWT头

4.2.2、有效载荷【用户信息】

4.2.3、签名哈希【防伪标志】

Base64URL算法:

4.3、JWT的用法

4.4.JWT优缺点

4.5、refresh token

4.6、session  token

5、单点登录

5.1、什么是单点登录?

5.2、“虚假”的单点登录(主域名相同)

5.3、“真实”的单点登录(主域名不同)

 标注:


0、HTTP是无状态的

        http协议是无状态的,也就是说http请求方和响应方无法维护状态,都是一次性的。但是在有的系统中,例如前面做过的OJ项目,都是刷题时,是需要用户登录后才能刷题。在这种情况下,我们是需要维护用户状态,否则用户就得不停地去登录登录,很影响用户体验感~

        那么,我们如何进行去维护用户的状态呢?

        标记!!!

        也就是说,我们可以给已经登录的用户进行一个标记。当后端登陆成功后,就给这个用户做一个标记,携带着这个标记返回到前端;前端获取到这个标记后,把这个标记存储起来;当前端后续再有请求发送给后端时,我们把这个标记带着;后端再次收到请求后,先验证这个标记是否合法,合法则进行后续逻辑操作,不合法就表示这个用户还未登陆。

        总结来说,就是:后端发标记——前端存标记——请求带标记

        具体落实下来,有以下几个方案:cookie+session、token


1、前端标记cookie

        前端存储,可以使用cookie、localStorage、sessionStorage等方式。如果采用cookie存储,cookie相比其他方式,借助http头、浏览器能力,cookie可以做到前端无感知。

        大致过程:

  • 在提供标记的接口(例如登录接口),通过HTTP返回头的Set-Cookie字段,直接存到浏览器上
  • 浏览器发起请求后,会自动把cookie通过HTTP请求头的Cookie字段,带给接口

1.1、cookie限制空间范围

        通过配置Domain / Path 来限制cookie的空间范围:Domain限制域,Path限制路径。

        Domain说明:Domain属性指定浏览器在发出HTTP请求时,哪些域名要附带这个cookie,如果没有指定这个属性,浏览器会默认是将其设为当前URL(存cookie的这个URL)的一级域名,例如www.baidu.com,就会设为baidu.com,并且如果访问baidu.com的任何子域名,HTTP请求也会带上这个cookie。并且如果服务器在Set-Cookie字段指定的域名不属于当前域名,浏览器会拒绝这个Cookie。也就是说,你自己本来的域名是aaa,你在Set-Cookie字段指定的域名是bbb,浏览器就会拒绝这个cookie。

        Path说明: Path属性指定浏览器发出HTTP请求时,

1.2、cookie限制时间范围

        通过配置Expires / Max-Age来限制cookie的时间范围~

        Expires说明:Expires属性指的是具体的到期时间,到了指定时间后,浏览器就不再保留这个cookie。这个值的格式为UTC格式~

        注:浏览器的时间是根据本地时间计算的,由于本地时间是不精确的,所以没有办法保证cookie一定会在服务器指定的时间过期~

        Max-Age说明:Max-Age属性,指的是这个cookie存在开始算起的秒数,秒数到了后,浏览器就不再存储这个cookie了

        注:上述两个属性同时设置了,Max-Age优先生效。

        注:如果不设置上述两个属性,或者将其设置为null,则表示cookie只在当前回话有效,浏览器关闭后,当前session结束,该cookie就会被删除~

1.3、cookie限制使用方式

        通过Secure / HttpOnly来限制cookie的使用方式~

        Secure说明:Secure属性指定浏览器只有在加密协议hTTPS下,才能将这个cookie发送给服务器。这个属性不需要我们自己来配置,他只是一个开关,如果当前协议是HTTP,浏览器就会默认关闭这个属性,如果是HTTPS就会自动打开这个开关~

        HttpOnly说明:HttpOnly属性也可以看作是一个开关,当我们把开关打开时,则指定该cookie无法通过js脚本(js中的document.cookie等操作)拿到这个值,防止cookie被脚本读到,也就是只有浏览器发出HTTP请求时,才会带上该cookie。


2、服务端存储session库

2.1、我们先来简单聊聊session是什么?

  1. session是用来记录用户状态的;
  2. session是由服务器端创建的;
  3. 同一个浏览器发起的多次请求,是同属于一次会话session;
  4. 首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId【唯一的】发送回客户端;
  5. 一次会话是使用同一浏览器发送的多次请求。一旦浏览器关闭,则结束会话;

        上述的简单了解后,我们知道他其实已经自动将session的SessionId放到了cookie中存储,也就是说前端的cookie中,存储了SessionId。在实际项目中,我们在使用session时,一般会在服务器端存储session会话,session回话中,包含sessionID,用户信息等,在我们有新的请求发送时,我们就可以直接获取cookie中存储的SessionID,然后在服务器端存储的session回话中查找,看有没有sessionID和请求中带过来的ID一样的会话,例如登录相关,有这个会话则表示已登录,无则表示用户未登录~

session的登录验证流程:

说明:

  • 浏览器登录发送账号密码,服务端查用户库,校验用户
  • 服务端把用户登录状态存为 Session,生成一个 sessionId
  • 通过登录接口返回,把 sessionId set 到 cookie 上
  • 此后浏览器再请求业务接口,sessionId 随 cookie 带上
  • 服务端查 sessionId 校验 session
  • 成功后正常做业务处理,返回结果

2.2、session的存储方式

        前端只是存了一个sessionId,session的具体信息,还是需要我们自己存储一下滴~

存储方式:

  • Redis(推荐):内存型数据库,redis中文官方网站。以 key-value 的形式存,正合 sessionId-sessionData 的场景;且访问快;
  • 内存:直接放到变量里。一旦服务重启就没了;
  • 数据库:普通数据库,如MySQL。性能不高。

2.3、session的过期和销毁

        删除存储的session中的数据即可~

2.4、session的分布式问题

        通常服务端是集群,而用户请求过来会走一次负载均衡,不一定打到哪台机器上。那一旦用户后续接口请求到的机器和他登录请求的机器不一致,或者登录请求的机器宕机了,session 不就失效了吗?

这个问题现在有几种解决方式。

  • 一是从「存储」角度,把 session 集中存储。如果我们用独立的 Redis 或普通数据库,就可以把 session 都存到一个库里。
  • 二是从「分布」角度,让相同 IP 的请求在负载均衡时都打到同一台机器上。以 nginx 为例,可以配置 ip_hash 来实现。

        但通常还是采用第一种方式,因为第二种相当于阉割了负载均衡,且仍没有解决「用户请求的机器宕机」的问题。

2.5、session的缺点

        session的维护给服务器端会造成很大的困扰,我们必须找地方存放它,又要考虑分布式问题,甚至还要给他启用一套redis集群~

这个缺点,token就有效解决了~


3、token

3.1、理解token 

        例如在登录中,我们其实不需要往session中存太多东西,我们完全可以把要存的数据(轻量级数据)都打包到cookie中,这样一来,服务器就不同存了~ 而每次的请求来了,我们只需要验证cookie中的“证件”是否有效就可以了。

        上述这种方式就被叫做token。

token的大致工作流程:

说明:

  • 用户登录,服务端校验账号密码,获得用户信息
  • 把用户信息、token 配置编码成 token,通过 cookie set 到浏览器
  • 此后用户请求业务接口,通过 cookie 携带 token
  • 接口校验 token 有效性,进行正常业务接口处理

3.2、客户端存储token

使用cookie或localStorage或sessionStorage等...

3.3、token过期

        把过期时间和数据一起放过去,验证时判断就可以了

3.4、token的编码

        token的编码是base64编码,我们可以搜索base64,随便打开一个编码网站,如下:

        上述这种把某些信息放在一起,通过base64编码后,好像没什么用。我大可以把cookie中的token值复制出来,解码,然后修改为我想要的用户的信息,再进行编码,放到cookie中,发送给后端,是不是就可以获取其他的用户信息了呢?

        答案是肯定的。那我们应该怎么办呢?

        针对上述这种操作,我们需要防止对token的数据这个数据的篡改!

        如何防篡改?给token签名!!!

        具体的我们可以根据JWT来看看,看看JWT是如何生成token的~

4、JWT

4.1、简单介绍JWT

        JWT是JSON WEB TOKEN的缩写,它是基于RFC7519标准定义的一种可以安全传输读的JSON对象,由于使用了数字签名,所以是可信任和安全全的。

        之所以使用JWT,是因为Token是属于无状态的,每个人定制的规则不同,生成的的结果就会不同。所以目前,多数都是采用JWT为统一令牌标准~

4.2、JWT的组成

jwt实例可以在这个网站看看效果:JSON Web Tokens - jwt.io

例如,我们就按照网页上默认的点击生成看看:

我们可以看到,编码后的结果是有三个部分组成的,每个部分之间用 . 分割【上述中,各个部分对应的字体颜色是一致的】。三个部分的含义:

  1. jwt头信息
  2. 有效载荷【用户信息】
  3. 签名哈希【防伪标志】

4.2.1、JWT头

 JWT头部分是一个描述JWT元数据的JSON对象,通常如下:

{
  "alg": "HS256",
  "typ": "JWT"
}

说明:

  • alg:表示签名使用的算法,默认为HMAC SHA256(HS256)
  • typ:表示令牌的类型,JWT令牌统一写为JWT

最后,使用Base64URL算法将上述JSON对象转换为字符串保存

4.2.2、有效载荷【用户信息】

        这一部分是JWT主体内容部分,也是一个JSON对象,包含需要传递的数据。JWT指定七个默认的字段供选择:

iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT

除了上述默认的字段外,我们还可以自定义私有字段,如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

        注:默认情况下,JWT是未加密的,也就是说其他人可以解读你的内容,所以不要构建隐私信息字段。

 最后,使用Base64URL算法将上述JSON对象转换为字符串保存

4.2.3、签名哈希【防伪标志】

        签名是对上面两部分数据签名。通过指定的算法生成哈希,以确保数据不会被篡改。

        首先,需要指定一个密钥(secret)。该密钥存在服务器中,不向用户公开。然后使用JWT头中指定的签名算法(HS256)根据下列公式,生成签名:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), 
secret)

        在计算出签名哈希后,JWT头、有效载荷、和签名哈希三个部分组成一个字符串,每个部分用“.”分隔,构成整个JWT对象

Base64URL算法:

        如前所述,JWT头和有效载荷序列化的算法都用到了Base64URL。该算法和常见Base64算法类似,稍有差别。 作为令牌的JWT可以放在URL中(例如api.example/?token=xxx)。 Base64中用的三个字符是"+","/“和”=",由于在URL中有特殊含义,因此Base64URL中对他们做了替换:"=“去掉,”+“用”-“替换,”/“用”_"替换,这就是Base64URL算法。

4.3、JWT的用法

        客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。

        此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。

4.4.JWT优缺点

  • JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
  • 生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
  • 存储在客户端,不占用服务端的内存资源
  • JWT默认不加密,但可以加密。生成原始令牌后,可以再次对其进行加密。
  • 当JWT未加密时,一些私密数据无法通过JWT传输。
  • JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
  • JWT本身包含认证信息,token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
  • 为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。

4.5、refresh token

        业务接口用来鉴权的 token,我们称之为 access token。越是权限敏感的业务,我们越希望 access token 有效期足够短,以避免被盗用。但过短的有效期会造成 access token 经常过期,过期后怎么办呢?

        一种办法是,让用户重新登录获取新 token,显然不够友好,要知道有的 access token 过期时间可能只有几分钟。

        另外一种办法是,再来一个 token,一个专门生成 access token 的 token,我们称为 refresh token。

  • access token 用来访问业务接口,由于有效期足够短,盗用风险小,也可以使请求方式更宽松灵活
  • refresh token 用来获取 access token,有效期可以长一些,通过独立服务和严格的请求方式增加安全性;由于不常验证,也可以如前面的 session 一样处理

有了 refresh token 后,几种情况的请求流程变成这样:

如果 refresh token 也过期了,就只能重新登录了。

4.6、session  token

        session和token的边界还是很模糊的,就像上面4.5提到的,refresh token也可能是以session的形式组织维护的。

        狭义上,我们通常认为session是前端存在cookie上,数据存在服务器端;token是前端存在哪儿都行,数据存在token里。非要对比这两个,其实就是在对比前端存哪儿,数据存哪儿~


5、单点登录

5.1、什么是单点登录?

        业务线越来越多,就会有更多业务系统分散到不同域名下,就需要「一次登录,全线通用」的能力,叫做「单点登录」。

5.2、“虚假”的单点登录(主域名相同)

        简单的,如果业务系统都在同一主域名下,比如wenku.baidu.com tieba.baidu.com,就好办了。可以直接把 cookie domain 设置为主域名 baidu.com,百度也就是这么干的。

5.3、“真实”的单点登录(主域名不同)

        比如滴滴公司,同时拥有didichuxing.com xiaojukeji.com didiglobal.com等域名,种 cookie 是完全绕不开的。

这要能实现「一次登录,全线通用」,才是真正的单点登录。

这种场景下,我们需要独立的认证服务(就是把登录业务单拎出来,放在一台服务器上),通常被称为 SSO(Single Sign On)。

一次从A系统引发登录,到B系统不用登录的完整流程:

说明:

  • 用户进入 A 系统,没有登录凭证(ticket),A 系统给他跳到 SSO
  • SSO 没登录过,也就没有 sso 系统下没有凭证(注意这个和前面 A ticket 是两回事),输入账号密码登录
  • SSO 账号密码验证成功,通过接口返回做两件事:一是种下 sso 系统下凭证(记录用户在 SSO 登录状态);二是下发一个 ticket
  • 客户端拿到 ticket,保存起来,带着请求系统 A 接口
  • 系统 A 校验 ticket,成功后正常处理业务请求
  • 此时用户第一次进入系统 B,没有登录凭证(ticket),B 系统给他跳到 SSO
  • SSO 登录过,系统下有凭证,不用再次登录,只需要下发 ticket
  • 客户端拿到 ticket,保存起来,带着请求系统 B 接口

「完整版本:考虑浏览器的场景」

上面的过程看起来没问题,实际上很多 APP 等端上这样就够了。但在浏览器下不见得好用。

看这里:

        对浏览器来说,SSO 域下返回的数据要怎么存,才能在访问 A 的时候带上?浏览器对跨域有严格限制,cookie、localStorage 等方式都是有域限制的。

这就需要也只能由 A 提供 A 域下存储凭证的能力。一般我们是这么做的:

 

图中我们通过颜色把浏览器当前所处的域名标记出来。注意图中灰底文字说明部分的变化。

  • 在 SSO 域下,SSO 不是通过接口把 ticket 直接返回,而是通过一个带 code 的 URL 重定向到系统 A 的接口上,这个接口通常在 A 向 SSO 注册时约定
  • 浏览器被重定向到 A 域下,带着 code 访问了 A 的 callback 接口,callback 接口通过 code 换取 ticket
  • 这个 code 不同于 ticket,code 是一次性的,暴露在 URL 中,只为了传一下换 ticket,换完就失效
  • callback 接口拿到 ticket 后,在自己的域下 set cookie 成功
  • 在后续请求中,只需要把 cookie 中的 ticket 解析出来,去 SSO 验证就好
  • 访问 B 系统也是一样

 标注:

        本文是根据下文魔改过来的,加了一些个人的观点

        文章: 鉴权必须了解的5个兄弟:cookie、session、token、jwt、单点登录 - 知乎

好啦,本文结束咯,下期见

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

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

相关文章

操作系统:文件管理(二)文件系统

一战成硕 4.3 文件系统4.3.1 文件系统结构4.3.2 文件系统布局4.3.3 外存空闲空间管理4.3.4 虚拟文件系统 4.3 文件系统 4.3.1 文件系统结构 4.3.2 文件系统布局 文件系统在磁盘中的结构 文件系统在内存中的结构 内存中的信息用于管理文件系统并通过缓存提高性能,这…

HDFS系统权限详解

一,HDFS超级用户 启动namenode的用户就是HDFS中的超级用户 如图所示 HDFS中,也是有权限控制的,其控制逻辑和Linux文件系统的完全一致 但是不同的是,两个系统的Supergroup不同(超级用户不同) Linux的操作用户是root HDFS文件系统的…

AI 编程界的扛把子

大家好,我是伍六七。 全国最大 AI 社群《AI 破局俱乐部》初创合伙人。8 年 Java 经验,干过开发,也做过管理。目前在某互联网大厂从事 Java 开发,业余时间研究 AI 编程。 我从 2022 年底,ChatGPT 问世,就密…

K8S知识点(五)

(1)资源管理介绍 Pod控制器的作用,就是为了最终产生各种各样的Pod,Pod里面运行容器,容器里面运行程序 程序需要数据持久化,可以用数据存储卷来存储 Pod想要让外部访问需要通过Service代理,外部…

基于Pytorch框架的LSTM算法(一)——单维度单步预测(1)

1.项目说明 使用data中的close列的时间序列数据完成预测【使用close列数据中的前windowback-1天数据完成未来一天close的预测】 2.数据集 Date,Open,High,Low,Close,Adj Close,Volume 2018-05-23,182.500000,186.910004,182.179993,186.899994,186.899994,16628100 2018-05…

IDEA高效调试,你真的会了吗

大家好,这里是 一口八宝周 👏 欢迎来到我的博客 ❤️一起交流学习 文章中有需要改进的地方请大佬们多多指点 谢谢 🙏 由于平时工作中经常需要debug调试代码,每次调试都会阻塞住进程,影响别人排查问题。 “你一个人deb…

Linux生成动态库

动态库 1.命名规则 Linux: libxxx.so lib :前缀(固定的);xxx:动态库的名字(自己取);.so:后缀(固定的); Windows&#…

.NET Framework中自带的泛型委托Action

Action<>是.NET Framework中自带的泛型委托&#xff0c;可以接收一个或多个输入参数&#xff0c;但不返回任何参数&#xff0c;可传递至多16种不同类型的参数类型。在Linq的一些方法上使用的比较多。 1、Action泛型委托 .NET Framework为我们提供了多达16个参数的Action…

链表面试OJ题(1)

今天讲解两道链表OJ题目。 1.链表的中间节点 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个…

轻量封装WebGPU渲染系统示例<19>- 使用GPU Compute材质多pass元胞自动机(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLifeMultiMaterialPass.ts 系统特性: 1. 用户态与系统态隔离。 细节请见&#xff1a;引擎系统设计思路 - 用户态与系统态隔离-CSDN博客 2. 高频调用与低频调…

1200*D. Same Differences(数学推公式)

Problem - 1520D - Codeforces 解析&#xff1a; 统计 a [ i ] - i #include<bits/stdc.h> using namespace std; #define int long long const int N2e55; int t,n,a[N]; signed main(){scanf("%lld",&t);while(t--){scanf("%lld",&n);…

一些对程序员有用的网站

当你遇到问题时 Stack Overflow&#xff1a;订阅他们的每周新闻和任何你感兴趣的主题Google&#xff1a;全球最大搜索引擎必应&#xff1a;在你无法使用Google的时候CSDN&#xff1a;聊胜于无AI导航一号AI导航二号 新闻篇 OSCHINA&#xff1a;中文开源技术交流社区 针对初学…

FPGA设计过程中有关数据之间的并串转化

1.原理 并串转化是指的是完成串行传输和并行传输两种传输方式之间的转换的技术&#xff0c;通过移位寄存器可以实现串并转换。 串转并&#xff0c;将数据移位保存在寄存器中&#xff0c;再将寄存器的数值同时输出&#xff1b; 并转串&#xff0c;将数据先进行移位&#xff0…

RHCSA --- Linux系统文件操作

rm -rf * 删除当前目录下的所有文件及目录&#xff0c;并且是直接删除&#xff0c;无需逐一确认命令行为 touch&#xff1a; 不存在时创建&#xff0c;存在时更新文件时间戳 touch 1 2 3 4 创建多个文件 touch {1..4}{2..4} 花括号展开创…

STM32_project:led_beep

代码&#xff1a; 主要部分&#xff1a; #include "stm32f10x.h" // Device header #include "delay.h"// 给蜂鸣器IO口输出低电平&#xff0c;响&#xff0c;高&#xff0c;不向。 //int main (void) //{ // // 开启时钟 // RC…

开关电源怎么进行老化测试?有哪些测试方法?

一、开关电源老化测试原理 开关电源老化测试是检测电源长期稳定性和可靠性的重要测试方法。通过模拟开关电源在实际工作环境(如高负荷、高温等)中的长时间使用&#xff0c;来验证其性能、稳定性和可靠性。老化测试的原理主要基于以下概念&#xff1a; 1. 加速老化原理 老化测试…

Ntrip协议是什么?(RTK)

NTRIP (Networked Transport of RTCM via Internet Protocol) 是一种将实时差分导航数据通过互联网传输的协议。它被广泛应用于全球卫星定位系统 (GNSS) 定位和导航领域&#xff0c;以提高 GNSS 定位的精度。 NTRIP 是基于 TCP/IP 的协议&#xff0c;使用 HTTP/1.1 进行数据传…

vue中异步更新$nextTick

1.需求 编辑标题, 编辑框自动聚焦 点击编辑&#xff0c;显示编辑框让编辑框&#xff0c;立刻获取焦点 2.代码实现 <template><div class"app"><div v-if"isShowEdit"><input type"text" v-model"editValue"…

leetcode链表

这几天手的骨裂稍微好一点了&#xff0c;但是还是很疼&#xff0c;最近学校的课是真多&#xff0c;我都没时间做自己的事&#xff0c;但是好在今天下午是没有课的&#xff0c;我也终于可以做自己的事情了。 今天分享几道题目 移除链表元素 这道题我们将以两种方法开解决&…

linux内的循环

格式 while 【 条件判断 】 do 语句体 done 上图 第一次代码&#xff0c;输入语句在外面&#xff0c;结果输入完&#xff08;非hello&#xff09;程序不断循环&#xff0c;没办法&#xff0c;ctrlc给程序终止了&#xff0c;然后把用户输入的语句放到了循环体里面…