如果有人问你:”你做了这么多年的开发,关于前端鉴权这块,能详细的说说吗?“。你该如何作答,脑海中有没有一个完整的思路。
像 Token、Cookie、Session、JWT、单点登录 这些概念,它们的作用、应用场景、如何使用和存储、安全性如何保障等等一系列问题,你能够应付的过来吗?
又如 认证、授权、鉴权、权限控制 以及它们之间的关系,你又是否真正的了解透彻?
1. 认证、授权、鉴权、权限控制
1.1 什么是认证?
认证(Identification)
是指根据声明者所特有的识别信息,确认声明者的身份。
白话文的意思就是:你需要用身份证证明你自己是你自己
。
比如我们常见的认证技术:
- 身份证
- 用户名和密码
- 用户手机:手机短信、手机二维码扫描、手势密码
- 用户的电子邮箱
- 用户的生物学特征:指纹、语音、眼睛虹膜
- 用户的大数据识别
- 等等
1.2 什么是授权?
授权(Authorization)
:在信息安全领域是指资源所有者
委派执行者
,赋予执行者
指定范围的资源操作权限,以便对资源的相关操作。
在现实生活领域例如: 银行卡(由银行派发)、门禁卡(由物业管理处派发)、钥匙(由房东派发),这些都是现实生活中授权的实现方式。
在互联网领域例如: web 服务器的 session 机制、web 浏览器的 cookie 机制、颁发授权令牌(token)等都是一个授权的机制。
1.3 什么是鉴权?
鉴权(Authentication)
在信息安全领域是指对于一个声明者所声明的身份权利,对其所声明的真实性进行鉴别确认的过程。
若从授权出发,则会更加容易理解鉴权。授权和鉴权是两个上下游相匹配的关系,先授权,后鉴权。
在现实生活领域: 门禁卡需要通过门禁卡识别器,银行卡需要通过银行卡识别器;
在互联网领域: 校验 session/cookie/token 的合法性和有效性
鉴权
是一个承上启下的一个环节,上游它接受授权的输出,校验其真实性后,然后获取权限(permission),这个将会为下一步的权限控制做好准备。
1.4 什么是权限控制?
权限控制(Access/Permission Control)
将可执行的操作定义为权限列表,然后判断操作是否允许/禁止
对于权限控制,可以分为两部分进行理解:一个是权限,另一个是控制。权限是抽象的逻辑概念,而控制是具体的实现方式。
在现实生活领域中: 以门禁卡的权限实现为例,一个门禁卡,拥有开公司所有的门的权限;一个门禁卡,拥有管理员角色的权限,因而可以开公司所有的门。
在互联网领域: 通过 web 后端服务,来控制接口访问,允许或拒绝访问请求。
1.5 认证、授权、鉴权和权限控制的关系?
看到这里,我们应该明白了认证
、授权
、鉴权
和权限控制
这四个环节是一个前后依次发生
、上下游
的关系;
需要说明的是,这四个环节在有些时候会同时发生。例如在下面的几个场景:
- 使用门禁卡开门: 认证、授权、鉴权、权限控制四个环节一气呵成,在瞬间同时发生
- 用户的网站登录: 用户在使用用户名和密码进行登录时,认证和授权两个环节一同完成,而鉴权和权限控制则发生在后续的请求访问中,比如在选购物品或支付时。
2. 前端鉴权方案
2.1 HTTP 基本鉴权
在 HTTP 中,基本认证方案(Basic Access Authentication)
是允许客户端(通常指的就是网页浏览器)在请求时,通过用户提供用户名和密码的方式,实现对用户身份的验证。
- 认证流程图
-
认证步骤解析
-
客户端(如浏览器): 向服务器请求一个
受限的列表数据或资源
,例如字段如下GET /list/ HTTP/1.1 Host: www.baidu.com Authorization: Basic aHR0cHdhdGNoOmY=
-
服务器:客户端你好,这个资源在安全区 baidu.com里,是受限资源,需要基本认证;
并且向客户端返回 401 状态码(Unauthorized 未被授权的)以及附带提供了一个认证域
www-Authenticate: Basic realm=”baidu.com”
要求进行身份验证;其中
Basic
就是验证的模式,而realm="baidu.com"
说明客户端需要输入这个安全域的用户名和密码,而不是其他域的HTTP/1.1 401 Unauthorizedwww-Authenticate: Basic realm= "baidu.com"
-
客户端: 服务器,我已经携带了用户名和密码给你了,你看一下;(注:如客户端是浏览器,那么此时会自动弹出一个弹窗,让用户输入用户名和密码);
输入完用户名和密码后,则客户端将用户名及密码以 Base64 加密方式发送给服务器
传送的格式如下 (其中 Basic 内容为:用户名:密码 的 ase64 形式):
GET /list/ HTTP/1.1Authorization: Basic Ksid2FuZzp3YW5n==
-
服务器: 客户端你好,我已经校验了
Authorization
字段你的用户名和密码,是正确的,这是你要的资源。HTTP/1.1 200 OK ...
-
-
优点
简单,基本所有流行的浏览器都支持
-
缺点
-
不安全:
由于是基于 HTTP 传输,所以它在网络上几乎是裸奔的,虽然它使用了 Base64 来编码,但这个编码很容易就可以解码出来。
即使认证内容无法被解码为原始的用户名和密码也是不安全的,恶意用户可以再获取了认证内容后使用其不断的享服务器发起请求,这就是所谓的重放攻击。
-
无法主动注销:
由于 HTTP 协议没有提供机制清除浏览器中的 Basic 认证信息,除非标签页或浏览器关闭、或用户清除历史记录。
-
-
使用场景
内部网络,或者对安全要求不是很高的网络。
几乎所有的线上网站都不会走该认证方案,所以该方案大家了解即可
2.2 Session-Cookie 鉴权
-
Session-Cookie
认证是利用服务端的 Session(会话)和 浏览器(客户端) 的 Cookie 来实现的前后端通信认证模式。 -
在理解这句话之前我们先简单了解下
什么是 Cookie
以及什么是 Session
? -
-
什么是 Cookie
众所周知,
HTTP 是无状态的协议
(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息);所以为了让服务器区分不同的客户端,就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态可以通过
Cookie
去实现。特点:
-
Cookie 存储在客户端,可随意篡改,不安全
-
有大小限制,最大为 4kb
-
有数量限制,一般一个浏览器对于一个网站只能存不超过 20 个 Cookie,浏览器一般只允许存放 300个 Cookie
-
Android 和 IOS 对 Cookie 支持性不好
-
Cookie 是不可跨域的,但是一级域名和二级域名是允许共享使用的(靠的是 domain)
-
-
什么是 Session
-
Session 的抽象概念是会话,是无状态协议通信过程中,为了实现中断/继续操作,将用户和服务器之间的交互进行的一种抽象;
-
具体来说,是服务器生成的一种 Session 结构,可以通过多种方式保存,如内存、数据库、文件等,大型网站一般有专门的 Session 服务器集群来保存用户会话;
-
原理流程:
-
- 客户端: 用户向服务器首次发送请求;
- 服务器: 接收到数据并自动为该用户创建特定的 Session / Session ID,来标识用户并跟踪用户当前的会话过程;
- 客户端: 浏览器收到响应获取会话信息,并且会在下一次请求时带上 Session / Session ID;
- 服务器: 服务器提取后会与本地保存的 Session ID进行对比找到该特定用户的会话,进而获取会话状态;
- 至此客户端与服务器的通信变成有状态的通信;
-
特点:
-
- Session 保存在服务器上;
- 通过服务器自带的加密协议进行;
-
与 Cookie 的差异:
-
- 安全性: Cookie 由于保存在客户端,可随意篡改,Session 则不同存储在服务器端,无法伪造,所以 Session 的安全性更高;
- 存取值的类型不同: Cookie 只支持字符串数据,Session 可以存任意数据类型;
- 有效期不同: Cookie 可设置为长时间保持,Session 一般失效时间较短;
- 存储大小不同: Cookie 保存的数据不能超过 4K;
-
看到这里可能就有同学想到了,
Session-Cookie
是不是就是把Session
存储在了客户端的Cookie
中呢?Bingo,的确是这样的,我们接着往下看
-
-
Session-Cookie 的认证流程图
-
-
Session-Cookie 认证步骤解析
-
客户端: 向服务器发送登录信息用户名/密码来请求登录校验;
-
服务器: 验证登录的信息,验证通过后自动创建 Session(将 Session 保存在内存中,也可以保存在 Redis 中),然后给这个 Session 生成一个唯一的标识字符串会话身份凭证
session_id
(通常称为sid
),并在响应头Set-Cookie
中设置这个唯一标识符;注:可以使用签名对
sid
进行加密处理,服务端会根据对应的secret
密钥进行解密 (非必须步骤) -
客户端: 收到服务器的响应后会解析响应头,并自动将
sid
保存在本地 Cookie 中,浏览器在下次 HTTP 请求时请求头会自动附带上该域名下的 Cookie 信息; -
服务器: 接收客户端请求时会去解析请求头 Cookie 中的
sid
,然后根据这个sid
去找服务端保存的该客户端的sid
,然后判断该请求是否合法;
-
-
Session-Cookie 的优点
-
- Cookie 简单易用
- Session 数据存储在服务端,相较于 JWT 方便进行管理,也就是当用户登录和主动注销,只需要添加删除对应的 Session 就可以了,方便管理
- 只需要后端操作即可,前端可以无感等进行操作;
-
Session-Cookie 的缺点
-
- 依赖 Cookie,一旦用户在浏览器端禁用 Cookie,那么就 GG 思密达了;
- 非常不安全,Cookie 将数据暴露在浏览器中,增加了数据被盗的风险(容易被 CSRF 等攻击);
- Session 存储在服务端,增大了服务端的开销,用户量大的时候会大大降低服务器性能;
- 对移动端的支持性不友好;
-
使用场景
-
- 一般中大型的网站都适用(除了 APP 移动端);
- 由于一般的 Session 需集中存储在内存服务器上(如 Redis),这样就会增加服务器的预算,所以预算不够请谨慎选择;
-
前端常用的 Session 库推荐
-
- 使用 express:express-session[1]
- 使用 koa:koa-session[2]