HTTP 是无状态的,所以无法分辨是谁发起的请求。
前后端分离中前后端的交互是通过 API 进行的,那么其中的认证是少不了的。前后端分离中常用的认证方式有下面几种:
- Session-Cookie 验证
- Token 验证
- OAuth(开放授权)
一、Session-Cookie 机制 (web应用中最常见的)
当服务端需要对访问的客户端进行身份认证时,常用的做法是通过session-cookie 机制;
session-cookie 工作流程:
不了解session 和cookie 的建议先去看这个文章:对session和cookie的认识
sequenceDiagram
客户端->>服务端: 将用户名密码发到服务器认证
服务端->>服务端: 服务端通过认证后,会缓存该会话(session),生成sessionID
服务端-->>客户端: 服务端set-cookie 设置cookie: sessionID = XX, 返回sessionID给客户端
客户端-)服务端: 浏览器会自动将服务器设置的Cookie附加在HTTP请求的头字段Cookie中。
服务端->>服务端: 服务端验证session, 服务端根据sessionID去查对应用户信息
服务端->> 客户端:如果有则直接将处理结果返回
Session-Cookie 认证存在的问题:
- 当客户访问量增加,服务端需要存储大量的session会话,对服务端有很大考验
- 当服务端为集群时,用户登录其中一台服务器,会将session保存在该服务器的内存中, 但是当用户访问其他服务器时。会无法访问。(已经有了成熟的解决方案)
- 可以采用使用缓存服务器来保证共享
- 第三方缓存来保存session
- 由于依赖cookie,所以存在CSRF安全问题
二、Token 认证机制:
token(令牌,访问资源的凭证) 认证是一种机制,具体的实现可以是一个随机的字符串,也可以是标准的jwt。
token需要查库验证token 是否有效,而JWT不用查库或者少查库,直接在服务端进行校验。
因为用户的信息及加密信息在第二部分payload和第三部分签证中已经生成,只要在服务端进行校验就行,并且校验也是JWT自己实现的。
这里主要说下jwt的实现。
具体实现JWT的相关介绍
JWT 是什么 ?
JWT 是 JSON Web Token的缩写.
是由3部分拼成的一个字符串,每个部分之间用.
分隔。
在HTTP通信 过程中,进行身份认证的一种方式。也可以在各个服务之间进行信息传输
是Token认证方式的一种具体实现
JWT的认证流程:
jwt的认证方式,服务端不需要保存任何session会话,是无状态的,比较容易扩展。
因为不依赖cookie,可以存在localStorage里,所以可以防御csrf攻击,更安全。
JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
sequenceDiagram
客户端->>服务端: 将用户名密码发到服务器认证
服务端->>服务端: 服务端通过认证后,签发token
服务端-->>客户端: 返回token给客户端
客户端-->>客户端: 存在loacalStorage 或者cookie里
客户端-)服务端: 请求时 将token放在请求头header或者参数里
服务端->>服务端: 服务端验证token
服务端->> 客户端: 返回用户请求的资源信息
放在cookie里会引起跨域,如何避免?
- 放在HTTP请求的头信息Authorization字段里。
Authorization: Bearer <token>
. - 另一种做法是,跨域的时候,token(jwt) 就放在 POST 请求的数据体里面。
config.headers.common['Authorization'] = `Bearer ${access_token || ''}`;
或者 axios.defaults.headers.common["token"] = this.token;
JWT 的数据结构 ?
JWT 默认是不加密的,所以不要把秘密信息放在这里。
- Header(头部): JSON,使用 Base64 URL 转成字符串,描述元数据
- Payload (负载): JSON,使用 Base64 URL 转成字符串,实际需要传递的数据
- JWT规定的7个官方字段:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
- 还可以定义私有字段:
- JWT规定的7个官方字段:
- Signature(签名): 对前面2部分的签名,防止数据篡改
- 首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户
- 使用 Header 里面指定的签名算法,按照下面的公式产生签名。
产生的签名
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Header 的JSON 对象
{
"alg": "HS256", // 表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256)
"typ": "JWT" // 表示令牌(token)的类型
}
大概的结果
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9. eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWT 安全性问题
- JWT 是明文编码: JWT 的编码是明文 Base64 的一个编码,是可以反编译的。在使用 JWT 传输信息的时候,不要放置重要敏感信息,最好使用 https。
JWT 泄露问题:
解决 JWT 的泄露问题是一个平衡的问题。有三种处理方式由轻到重,看你业务重要性酌情选择:
- 将 JWT 的过期时间设置的很短,即使泄露也无关紧要。或者旧的直接加入黑名单
- 在服务端设计 JWT 的黑名单机制,将泄露的 Token 加黑名单即可。
- 保存签发的 JWT,当 JWT 泄露时,直接设置失效。
JWT 的优点
- 轻量级:JWT是非常轻量级的,传输的方式多样化,可以通过URL/POST参数/HTTP头部等方式传输。(一般放在 x-access-token里)
- 无状态/跨域认证:令牌包含所有用于标识用户的信息,这消除了对会话状态的需要。 如果我们使用负载平衡器,我们可以将用户传递给任何服务器,而不是绑定到我们登录的同一台服务器上。
- 可重用性/扩展性:我们可以有许多独立的服务器在多个平台和域上运行,并重复使用相同的令牌来验证用户。 构建与另一个应用程序共享权限的应用程序很容易。
- 安全性:无需担心跨站请求伪造(CSRF)攻击。
JWT 的缺点
JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑
使用场景
- 利用token 可以防止表单重复提交(主要说的是后端限制)
- 前端可以通过按钮置灰防止表单提交
- 后端的话就是验证request里的token 是否和session里的token相等,从而判断这个表单是否提交过
- 用户身份验证(授权):这是最常见的使用场景,解决单点登录问题。因为JWT使用起来轻便,开销小,服务端不用记录用户状态信息(无状态),所以使用比较广泛;
- 信息交换:JWT是在各个服务之间安全传输信息的好方法。因为JWT可以签名,例如,使用公钥/私钥对儿 - 可以确定请求方是合法的。此外,由于使用标头和有效负载计算签名,还可以验证内容是否未被篡改。
三、OAuth 认证:
OAuth(Open Authorization)是一个开放标准,允许用户授权第三方网站访问他们存储在服务端的用户信息。
我们常见的的 QQ、微信等第三方登录便是 Auth 认证方式。
- OAuth 协议有 1.0 和 2.0(目前最主要的用户身份验证和授权方式) 两个版本。
- 相比较 1.0 版,2.0 版整个授权验证流程更简单更安全,
OAuth 更像是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
在单纯的前后端分离系统中,OAuth 并不是常用的方式,它更多的应用在不同系统之间的授权交互。
四、session-cookie机制 和token机制的对比:
首先,当前后端分离时我们会因为同源策略而无法设置cookie和sessionid。当然了我们有很多方式去解决这个问题,比如反向代理和jsonp等。但这仍然不如直接使用jwt来的简便。其次就是要说到jwt与传统的身份认证相比有什么优势了。
session-cookie 机制 | jwt认证机制 | |
---|---|---|
跨域 | cookie 不允许跨域访问 | 可以跨域认证 |
安全性 | 依赖cookie,容易被CSRF | 不依赖cookie 更安全 |
扩展性 | ios等原生平台没有cookie | 扩展性更好 |
数据存储 | 数据存在服务端 | 数据存在jwt里 |
性能 | 服务端需要保存session,大量查询时性能较差 | HMACSHA256计算 |
五、总结:
session-cookie方案 就是利用cookie来管理session,即把 Session 放入 HTTP 响应中还给客户端,并保存在客户端,当客户端发送下一次请求的时候,就把这个 Session 一起发送回来,这样就能这次的请求是谁发出来的了。
而 Token 方案 也就是JWT 相对来说 不依赖cookie,更安全,原生平台也可以用,各个系统之间也可以,允许跨域认证,扩展性更好。而jwt为了防止泄露,应该将有效期设置的比较短,为了减少盗用, 最好使用HTTPS协议传输,因为HTTP是明码传输的
个人觉得 token认证和session认证 需要根据自己的业务去选择,虽然session认证有缺点, 但是现在其实已经有比较成熟的解决方案了。相对来说的话,token的扩展性和安全性都更好一些