浏览器系列 — cookie、session、Token、JWT及对应的登录态机制
首先清楚三个概念:
认证
- 通俗地讲就是
验证当前用户的身份
,证明“你是你自己” - 互联网中的认证:
- 用户名密码登录
- 邮箱发送登录链接
- 手机号接收验证码
- 只要你能收到邮箱/验证码,就默认你是账号的主人
授权
- 用户
授予第三方应用
访问该用户某些资源的权限- 你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)
- 你在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)
- 实现授权的方式有:cookie、session、token、OAuth
凭证
- 实现认证和授权的前提是需要一种媒介(证书) 来
标记访问者的身份
- 相当于每个人的身份证
比如掘金会有两种模式:`游客模式`和`登录模式`。
游客模式下,可以正常浏览网站上面的文章,一旦想要点赞/收藏/分享文章,就`需要登录或者注册账号`。
当用户登录成功后,服务器会给该用户使用的浏览器颁发一个令牌(`token`),此令牌用来`表明你的身份`,
`每次`浏览器发送请求时`会带上`这个令牌,就可以使用游客模式下无法使用的功能
用户登录方案
- Cookie + Session 作登录态
- Token 作登录态
- OAuth 第三方登录
Cookie + Session 作登录态
前言引入
我们以 <商城及购物车> 为例子作引入:
对于商城首页
,所有用户浏览的商品都是一样的
情况下,用户不用登录也可以访问。当时如果用户选择商品加入购物车
或添加到收藏夹
的时候,我们就需要有可以标识用户身份
的凭证,这就可以采用 cookie + session 的机制来作登录态
什么是 session
用户在某个网站首次登录,此时浏览器发起请求给服务端,服务端
会为这次请求临时
开辟一块内存空间
,存的便是session对象
,session对象存的内容就是记录用户的一些状态
或行为记录
那么问题来了,服务端如何知道收到的请求是哪个用户操作浏览器发起的呢?于是cookie就出场了
什么是 cookie
简单来说,cookie是服务器通过在响应头中的Set-Cookie
字段发送到用户的浏览器并保存在本地
的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带
并发送到服务器上。它用来保持用户登录状态
,和session配合使用可以用来交流清楚是哪位用户
关于cookie的详细内容见 浏览器系列 -- 本地存储
cookie 和 session 的区别
- 存放位置:cookie在浏览器,session在服务端(一般是在内存中)
购物车的数据一般放在`数据库`中,session的目的不是存购物车的数据,而是作为让服务端知道是哪位用户的`工具`罢了。
为什么session不存购物车的数据,因为cookie到期用户被退出登录,重新登录后session被替代掉,意味着购物车的数据将被清空
- 安全系数:cookie安全系数低,session
安全系数高
- 有效时间:cookie看设置的
有效期
,如果没有设置则是窗口关闭就消失,session在内存也是窗口关闭就消失,在数据库里理论上可以很久
- 性能方面:cookie不会造成服务端压力大,用户数过大时,session会造成
服务器压力大
- 存储内容:cookie存的数据一般是用户
昵称
、账号
等一些非隐私数据,而session一般存密码
、一些ID
之类的隐私数据 - 存储的数据类型:cookie是
字符串类型
,而session可以是任何类型,主要是键值对的哈希表类型
或Object类型
cookie和session的联系
两者都是为了跟踪浏览器用户身份的会话方式,两者相互配合
可以作登录态
接下来看一下 cookie 和 session 是如何配合作登录态的:
实现流程
- 用户首次登录
用户首次登录后,服务器服务端
会创建该用户对应的session
和session id
,我把session
比喻成一把锁,把session id
比喻成开这把锁的一把钥匙,然后服务端把这把钥匙通过发送响应头的方式(将session id放在响应头header的Set-Cookie
字段里面),浏览器收到后把session id放在cookie
里面,这时cookie的有效期就等于这把钥匙的有效期,也就是说cookie一旦过期,登录态就作废
,表示用户退出登录(属于被动退出)
- 登录之后的访问
用户当前处于登录态,然后访问该网站并发起http请求(比如将商品加入购物车),此时浏览器会自动携带该用户的cookie,(可能是拿取存放session id的cookie),服务端这边要是得知这把锁被打开了,就跑去数据库拿该用户存在数据库的数据(购物车)并返回。但要是打不开,比如cookie过期,服务器会返回状态码401
,浏览器收到之后会要求用户重新输入账号密码登录
Token 作登录态
为什么选择使用token代替session+cookie作登录态?
- 服务器压力大:通常session是存储在内存中的,用户数增多时,内存空间被挤爆
- cookie过期代表用户被退出登录,体验感极差
- cookie容易遭受CSRF攻击
- 如果禁用cookie,就用token来作登录态
分类
- acesss token:访问资源接口时所需要的
资源凭证
access token 基本组成部分:
1. uid (用户唯一的身份标识)
2. time (当前时间的时间戳)
3. sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
- refresh token:专用于
刷新 access token
的 token
如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户`重新输入`登录用户名与密码,会很麻烦
如何使用 access token 作登录态
- 用户首次登录,服务器对用户名和密码进行检验,验证成功后生成
加密
的token
并返回(响应头
里面),浏览器收到token后放在cookie
或localstorage
里面【注意此时服务器不保存
token】 - 用户当前处于登录态,然后访问该网站并发起http请求(比如将商品加入购物车),此时携带token放在
请求头
里面发送给服务器 - 服务器根据
JWT算法
解密和检验 token ,验证成功,保持登录态
,要是验证失败,会在响应头返回状态码401
,浏览器这边收到会使用 refresh token 刷新 access token
这波是用解析 token 的时间
换 session 的存储空间
,减轻服务器的压力
关于JWT算法:简单来说就是对token进行解密,解密后判断是否可用(/过期),直接表明登录态是否保持
如何使用 refresh token 刷新 access token
要是 access token 验证失败,则浏览器这边需要对 access token 进行更新,方法是使用 refresh token
- access token 的有效期比较短(比如是一周), refresh token 的有效期比较长(比如一个月),当 acesss token 过期失效但 refresh token 未过期,则使用 refresh token 就可以获取到新的 token
- 如果 refresh token 也失效了,用户就只能
重新登录
了 - refresh token 及过期时间是存储在服务器的数据库中,只有在
需要申请新的 acesss token 时才会
验证,不会对业务接口响应时间造成影响,也不需要向 session 一样一直保持在内存中以应对大量的请求
OAuth 第三方登录
OAuth 机制实现流程
这里以微信开放平台的接入流程为例:
- 网站运营者申请账户
- 首先,a.com 的运营者需要在微信开放平台注册账号,并向微信申请使用微信登录功能。
- 申请成功后,得到申请的
appid
、appsecret
。
- 用户登录并授权
- 用户在 a.com 上选择使用微信登录。
- 这时会跳转微信的 OAuth 授权登录,并带上 a.com 的回调地址。
- 用户输入微信账号和密码,登录成功后,需要选择具体的授权范围,如:授权用户的头像、昵称等。
- 微信生成临时票据
- 授权之后,微信会根据拉起 a.com?code=123 (或重定向到第三方),带上
临时票据 code
。
- 网站向微信索取 access token
- 获取 code 之后, a.com 会拿着 code 、appid、appsecret,向微信服务器
申请 token
,验证成功后,微信会下发一个 token。 - 有了 access token 之后, a.com 就可以用 access token 调用微信接口,拿到对应的微信用户头像,用户昵称等信息了。
- a.com 提示用户登录成功,并将登录状态写入 cookie,以作为后续访问的凭证。
其他平台的接入方式可以去对应得官方文档查看,流程基本类似。
参考文章
- 傻傻分不清之 Cookie、Session、Token、JWT
- 前端常见登录实现方案 + 单点登录方案
- 看完这篇 Session、Cookie、Token,和面试官扯皮就没问题了