9

鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录

 2 years ago
source link: https://blog.csdn.net/qq_34261347/article/details/120650207
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录

同时被 2 个专栏收录
33 篇文章 0 订阅
18 篇文章 0 订阅

从状态说起

[HTTP 无状态]

我们知道,HTTP是无状态的,也就是说,HTTP请求方和响应方间无法维护状态,都是一次性的,它不知道前后的请求都发生了什么

但有的场景下,我们需要维护状态,最常见的,一个用户登录微博,发布,关注,评论,都是应该在登录后的用户状态下的

在学校或公司,入学入职那一天起,会录入你的身份、账户信息,然后给你发个卡,今后在园区内,你的门禁、打卡、消费都只需要刷这张卡

[前端存储]

这就涉及一发,一存,一带,发好办,登录接口直接返回给前端,存储就需要前端想办法了,前提是,你要把卡带在身上

前端的存储方式有很多

  • 挂载到全局变量上,但这是个[体验卡],一次刷新页面就没了
  • 可以存到cookie,localStorage里,这属于[会员卡],无论怎么刷新,只要浏览器没清掉或者过期,就一直拿着这个状态
基石:cookie

可是前端好麻烦啊,又要自己存,又要想办法带出去,有没有不用操心的?

有,cookie

cookie也是前端存储的一种,但相比于localStorage等其他方式,借助HTTP头,浏览器能力,cookie可以做到前端无感知

一般过程是这样的:

  • 在提供标记的接口,通过 HTTP 返回头的 Set-Cookie 字段,直接「种」到浏览器上
  • 浏览器发起请求时,会自动把 cookie 通过 HTTP 请求头的 Cookie 字段,带给接口
[配置:Domain / Path]

你不能拿清华的校园卡进北大

cookie 是要限制:通过Domain(域) / Path(路径)两级(空间范围)

Domain属性指定浏览器发出 HTTP 请求时,哪些域名要附带这个 Cookie。如果没有指定该属性,浏览器会默认将其设为当前 URL 的一级域名,比如 www.example.com 会设为 example.com,而且以后如果访问example.com的任何子域名,HTTP 请求也会带上这个 Cookie。如果服务器在Set-Cookie字段指定的域名,不属于当前域名,浏览器会拒绝这个 Cookie。

Path属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。只要浏览器发现,Path属性是 HTTP 请求路径的开头一部分,就会在头信息里面带上这个 Cookie。比如,PATH属性是/,那么请求/docs路径也会包含该 Cookie。当然,前提是域名必须一致

[配置:Expires / Max-Age]

你毕业了卡就不好使了

cookie 还可以限制 通过Expires,Max-Age中的一种 (时间范围)

Expires属性指定一个具体的到期时间,到了指定时间以后,浏览器就不再保留这个 Cookie。它的值是 UTC 格式。如果不设置该属性,或者设为null,Cookie 只在当前会话(session)有效,浏览器窗口一旦关闭,当前 Session 结束,该 Cookie 就会被删除。另外,浏览器根据本地时间,决定 Cookie 是否过期,由于本地时间是不精确的,所以没有办法保证 Cookie 一定会在服务器指定的时间过期。

Max-Age属性指定从现在开始 Cookie 存在的秒数,比如60 * 60 * 24 * 365(即一年)。过了这个时间以后,浏览器就不再保留这个 Cookie。
如果同时指定了Expires和Max-Age,那么Max-Age的值将优先生效。
如果Set-Cookie字段没有指定Expires或Max-Age属性,那么这个 Cookie 就是 Session Cookie,即它只在本次对话存在,一旦用户关闭浏览器,浏览器就不会再保留这个 Cookie

[配置:Secure / HttpOnly]

有的学校规定,不带卡套不让刷(什么奇葩学校,假设);有的学校不让自己给卡贴贴纸。

Secure属性指定浏览器只有在加密协议 HTTPS 下,才能将这个 Cookie 发送到服务器。另一方面,如果当前协议是 HTTP,浏览器会自动忽略服务器发来的Secure属性。该属性只是一个开关,不需要指定值。如果通信是 HTTPS 协议,该开关自动打开

HttpOnly属性指定该 Cookie 无法通过 JavaScript 脚本拿到,主要是Document.cookie属性、XMLHttpRequest对象和 Request API 都拿不到该属性。这样就防止了该 Cookie 被脚本读到,只有浏览器发出 HTTP 请求时,才会带上该 Cookie

[HTTP 头对cookie的读写]

HTTP 返回的一个 Set-Cookie 头用于向浏览器写入「一条(且只能是一条)」cookie,格式为 cookie 键值 + 配置键值

Set-Cookie: username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

那我想一次多 set 几个 cookie 怎么办?多给几个 Set-Cookie 头(一次 HTTP 请求中允许重复)

[前端对cookie的读写]

前端可以自己创建 cookie,如果服务端创建的 cookie 没加HttpOnly,那恭喜你也可以修改他给的 cookie。

调用document.cookie可以创建、修改 cookie,和 HTTP 一样,一次document.cookie能且只能操作一个 cookie

document.cookie = 'username=jimu; domain=jimu.com; path=/blog; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly';

调用document.cookie也可以读到 cookie,也和 HTTP 一样,能读到所有的非HttpOnly cookie

console.log(document.cookie);// username=jimu; height=180; weight=80 

那有了存储工具,接下来怎么做呢?

应用方案:服务端session

现在回想下,你刷卡的时候发生了什么?

其实你的卡上只存了一个 id(可能是你的学号),刷的时候物业系统去查你的信息、账户,再决定「这个门你能不能进」「这个鸡腿去哪个账户扣钱」

这种操作,在前后端鉴权系统中,叫 session

典型的 session 登陆/验证流程:
在这里插入图片描述

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

服务端只是给 cookie 一个 sessionId,而 session 的具体内容(可能包含用户信息、session 状态等),要自己存一下。存储的方式有几种:

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

[Session 的过期和销毁]

很简单,只要把存储的 session 数据销毁就可以

应用方案:token

我又想到学校,在没有校园卡技术以前,我们都靠「学生证」。门卫小哥直接对照我和学生证上的脸,确认学生证有效期、年级等信息,就可以放行了

回过头来想想,一个登录场景,也不必往 session 存太多东西,那为什么不直接打包到 cookie 中呢?这样服务端不用存了,每次只要核验 cookie 带的「证件」有效性就可以了,也可以携带一些轻量的信息

这种方式通常被叫做 token
在这里插入图片描述
token的流程是这样的:

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

狭义上,我们通常认为 session 是「种在 cookie 上、数据存在服务端」的认证方案,token 是「客户端存哪都行、数据存在 token 里」的认证方案。对 session 和 token 的对比本质上是「客户端存 cookie / 存别地儿」、「服务端存数据 / 不存数据」的对比。

前面我们已经知道了,在同域下的客户端/服务端认证系统中,通过客户端携带凭证,维持一段时间内的登录状态。

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

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

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

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

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

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

这种场景下,我们需要独立的认证服务,通常被称为 SSO
在这里插入图片描述

  1. 用户进入A系统,没有登录凭证(ticket),A系统给他跳到SSO
  2. SSO没登录过,也就没有sso系统下没有凭证(注意这个和前面 A ticket是两回事),输入账号密码登录
  3. SSO账号密码验证成功,通过接口返回做两件事,一是种下sso系统下凭证(记录用户登录状态);二是下发一个ticket
  4. 客户端拿到ticket,保存起来,带着请求系统A接口
  5. 系统A检验ticket,成功后正常处理业务请求
  6. 此时用户第一次进入系统B,没有登录凭证(ticket),B系统给他跳到SSO
  7. SSO登录过,系统下有凭证,不用再次登录,只需要下发ticket
  8. 客户端拿到ticket,保存起来,带着请求系统B接口
  • HTTP是无状态的,为了维持前后请求,需要前端存储标记
  • cookie 是一种完善的标记方式,通过 HTTP 头或 js 操作,有对应的安全策略,是大多数状态管理方案的基石
  • session 是一种状态管理方案,前端通过 cookie 存储 id,后端存储数据,但后端要处理分布式问题
  • token 是另一种状态管理方案,相比于 session 不需要后端存储,数据全部存在前端
  • token 的编码技术,通常基于 base64,或增加加密算法防篡改,jwt 是一种成熟的编码方案
  • session 和 token 的对比就是「用不用cookie」和「后端存不存」的对比
  • 单点登录要求不同域下的系统「一次登录,全线通用」,通常由独立的 SSO 系统记录登录状态、下发 ticket,各业务系统配合存储和认证 ticket

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK