从状态说起

[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
1

那我想一次多 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';
1

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

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

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

应用方案:服务端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

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

  1. 【鉴权/授权】一步一步实现一个简易JWT鉴权

    微信公众号:趣编程ACE 关注可了解.NET日常开发技巧.如需源码,请公众号留言 源码; **[如果您觉得本公众号对您有帮助,欢迎下方扫码加入群聊] 鉴权.授权专题之简易鉴权 我记得作为实习生去公司上 ...

  2. Kong 优雅实现微服务网关鉴权,登录场景落地实战篇

    目录 登录实现 B 端登录之后,浏览器存 cookie 登录代码实现细节,cookie设计 网关介绍 API 网关是什么 为什么需要网关 从技术角度来看,什么是Kong? 为什么使用 Kong Kon ...

  3. SpringBoot项目的用户鉴权分析

    一.鉴权类:UserAuthFilter springBoot被称为开箱即用,是因为许多代码都帮开发者实现了,就连用户鉴权部分都帮我们写好了,如需自定义过滤器,则继承UserAuthFilter类即可 ...

  4. 注册登录鉴权以及购物车常见管理

    这里写自定义目录标题 注册鉴权以及购物车系统相关知识点 对称加密和非对称加密: **jwt**包含三部分: **登录**分为**授权和鉴权** 注册鉴权以及购物车系统相关知识点 ** 对称加密和非对称 ...

  5. SpringBoot系列: Web应用鉴权思路

    ============================== web 项目鉴权 ============================== 主要的鉴权方式有: 1. 用户名/密码鉴权, 然后通过 S ...

  6. postman cookie设置_接口鉴权之cookie,session和token

    什么是接口鉴权? 鉴权就是鉴定权限.在公司开发的一些系统中都会有权限的鉴定.不管是app还是网站的项目,都会有登录模块,而只要有登录模块,他有一些功能,肯定是必须要登录之后才能完成了.比如你在淘宝下单 ...

  7. js获取session_学习后端鉴权系列: 基于Cookie, Session认证

    说起鉴权大家应该都很熟悉, 不过作为前端开发来讲, 鉴权的流程大头都在后端小哥那边, 但是作为一个有志气的开发者肯定要好好学习整个鉴权流程以及方案, 不然怎么跟后端合作. 常见的鉴权方案 基于Cook ...

  8. 前后端鉴权方案,一文打尽!

    前言 还记得之前在面试的时候,有一位面试官就问了,关于前端鉴权这块,Token.Cookie.Session.JWT.单点登录是什么?有什么作用?你一般是怎么做的?以及你是怎么存储的呢?那你又是怎么保 ...

  9. API 鉴权插件上线!支持用户自定义鉴权插件

    0.4.0 版本更新主要围绕这几个方面: 分组独立的 UI,支持分组 API 鉴权 API 测试支持继承 API 鉴权 支持用户自定义鉴权插件,仅需部分配置即可发布鉴权插件 开始介绍功能之前,我想先和 ...

最新文章

  1. 整理的16个有用的jQuery Form(表单)验证教程
  2. 谈asp.net解决方案的项目生成时的输出路径
  3. font HTML语言,HTML font 标签
  4. Cloudera将被私有化,Hadoop时代或将落幕
  5. mysql和oracle转换_转MySql 与Oracle区别
  6. vue3 @/cli脚手架搭建项目
  7. WPF窗体隐藏鼠标光标的方法
  8. javaWeb:相关监听方法汇总
  9. 矩阵迹(trace), 行列式(determinate)
  10. 不知道吧?未加工的食物可以帮助你减肥
  11. MySQL:指定索引+事务+存储引擎的配置 开发必备 天呐!为什么会有索引这种东西
  12. ssi 指令 php,SSI使用详解(二)_PHP教程
  13. Method findById should have no parameters
  14. CH455 数码管驱动以及键盘控制芯片 应用笔记
  15. c语言程序设计植树,c语言程序设计报告
  16. 小傻蛋的妹妹跟随小甲鱼学习Python的第十节010
  17. 相片打印机原理_相片打印机怎么打印? 2021照片打印机(手机照片打印机)推荐...
  18. 向日葵链接失败的解决办法
  19. Python pymysql 插入数据一直不成功
  20. 内生性问题—广义矩估计

热门文章

  1. kotlin 查找id_Kotlin程序查找等边三角形的区域
  2. Java BufferedWriter close()方法与示例
  3. arraylist能否接收强转类型_ArrayList 源码解析
  4. 校园计算机网络系统,校园计算机网络系统
  5. matlab7.0 6.5,任何处理matlab6.5与7.0.1的兼容问题
  6. java web截屏_java_WebDriver中实现对特定的Web区域截图方法,用过 WebDriver 的同学都知道,We - phpStudy...
  7. 请检查virtualboxapi是否正确安装_电机行业安装绝缘轴承规范
  8. c++ abort 函数_C ++中带有示例的abort()函数
  9. Java ObjectInputStream readDouble()方法与示例
  10. java 方法 示例_Java集合的lastlastIndexOfSubList()方法和示例