OAuth2+JWT新一代认证技术

 OAuth2四种认证模式,授权许可是表示客户用来获取访问令牌的资源所有者授权的凭证。此规范协议规定了4种授权类型:

authorization code(授权码模式)

  1. 用户访问客户端,客户端通过用户代理向认证服务器请求授权码;
  2. 用户同意授权;
  3. 认证服务器通过用户代理返回授权码给客户端;
  4. 客户端携带授权码向认证服务器请求访问令牌(AccessToken);
  5. 认证服务器返回访问令牌;
  6. 客户端携带访问令牌向资源服务器请求资源;
  7. 资源服务器返回资源。


implicit(简化模式)

1、用户访问客户端,客户端通过用户代理向认证服务器请求授权码;
2、用户同意授权;
3、认证服务器返回一个重定向地址,该地址的url的Hash部分包含了令牌;
4、用户代理向资源服务器发送请求,其中不带令牌信息;
5、资源服务器返回一个网页,其中包含的脚本可以获取Hash中的令牌;
6、用户代理执行脚本提取令牌;
7、用户代理将令牌返回给客户端;
8、客户端携带令牌向资源服务器请求资源;
9、资源服务器返回资源。


resource owner password credentials(密码模式)

  1. 用户向客户端提供用户名密码;
  2. 客户端将用户名和密码发给认证服务器请求令牌;
  3. 认证服务器确认无误后,向客户端提供访问令牌;
  4. 客户端携带令牌向资源服务器请求访问资源;
  5. 资源服务器返回资源。


client credentials(客户端模式)

  1. 客户端向认证服务器进行身份认证,并要求一个访问令牌;
  2. 认证服务器确认无误后,向客户端提供访问令牌;
  3. 客户端携带令牌向资源服务器请求访问资源;
  4. 资源服务器返回资源。

 

OAuth2授权开放标准,通过认证用户身份,颁发token(令牌),使第三方在限定时间内,限定范围内访问指定资源。

OAuth2使用token验证用户登录合法性,但token不能携带用户信息,资源服务器无法在本地进行验证,每次向资源访问,资源服务器都向认证服务器发起请求,验证token有效性,获取token对应的用户信息,大量的请求,处理效率低,获取token对应的用户信息。

jwt就是特殊的token:包括 头部,载荷,签名,适用于一次性的身份认证,api鉴权,不要试图用jwt代替session

jwt的构成:

第一部分称为头部(Header
第二部分称为载荷(Payload
第三部分称为签证(Signature
因此JWT通常如下所示:xxxx.yyyyy.zzzzz Header.Payload.Signature

  1. Header,承载两部分信息:

声明类型:这里是JWT

声明加密算法:通常直接使用HMAC SHA256RSA。它会使用Base64编码组成JWT结构的第一部分,注意Base64是一种编码,也就是说它时可以被翻译成原来的样子的,并不是一种加密过程。

  1. Payload, 令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的声明,同样是使用Base64编码组成JWT结构的第二部分,,载荷就是存放有效信息的地方,这些有效信息包含三个部分:标准中注册的声明、公共的声明、私有的声明

标准中注册的声明 (建议但不强制使用) :

iss: jwt签发者

sub: jwt所面向的用户

aud: 接收jwt的一方

exp: jwt的过期时间,这个过期时间必须要大于签发时间

nbf: 定义在什么时间之前,该jwt都是不可用的.

iat: jwt的签发时间

jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

3、signature,JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)

payload (base64后的)

secret  【密钥】

这个部分需要base64加密后的headerbase64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。【保证数据的安全】

将这三部分用.连接成一个完整的字符串,构成了最终的jwt

jwt优点

因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。

因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。

便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。

它不需要在服务端保存会话信息, 所以它易于应用的扩展

安全相关

不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。

保护好secret私钥,该私钥非常重要。

如果可以,请使用https协议

【在互联网上没有绝对的安全,只有相对的安全】

token认证流程

客户端发送账号和密码请求登录

服务端收到请求,验证账号密码是否通过

验证成功后,服务端会生成唯一的 token,并将其返回给客户端

客户端接受到 token,将其存储在 cookie 或者 localStroge 中

之后每一次客户端向服务端发送请求,都会通过 cookie 或者header 携带该 token

服务端验证 token 的有效性,通过才返回响应的数据

Token认证优点

支持跨域访问:Cookie 是不允许跨域访问的,这一点对 Token 机制是不存在的,前提是传输的用户认证信息通过 HTTP 头传输

无状态: Token 机制在服务端不需要存储 session 信息,因为 Token 自身包含了所有登录用户的信息,只需要在客户端的 cookie 或本地介质存储状态信息

适用性更广: 只要是支持 http 协议的客户端,就可以使用 token 认证。

无需考虑CSRF: 由于不再依赖 cookie,所以采用 token 认证方式不会发生 CSRF,所以也就无需考虑 CSRF 的防御

Jwt认证流程:

首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探

后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载)、将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形同111.zzz.xxx的字符串

后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localstorage或sessionStorage上,退出登录时前端删除保存的JWT即可

前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)

后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)

验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果

Jwt优势:

简洁(Compact):可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快

自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库

因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持

不需要在服务端保存会话信息,特别适用于分布式微服务

Jwt能做什么

授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用。

信息交换:JSON Web Token是在各方之间安全地传输信息的好方法。因为可以对JWT进行签名(例如,使用公钥/私钥对),所以您可以确保发件人需要是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否遭到募改。

基于session认证所显露的问题

认证方式: 我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。

认证流程:

暴露问题:

- 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大

- 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

- 因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

- 在前后端分离系统中就更加痛苦:如下图所示

也就是说前后端分离在应用解耦后增加了部署的复杂性。通常用户一次请求就要转发多次。如果用session 每次携带sessionid 到服务器,服务器还要查询用户信息。同时如果用户很多。这些信息存储在服务器内存中,给服务器增加负担。还有就是CSRF(跨站伪造请求攻击)攻击,session是基于cookie进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。还有就是sessionid就是一个特征值,表达的信息不够丰富。不容易扩展。而且如果你后端应用是多节点部署。那么就需要实现session共享机制。不方便集群应用。

猜你喜欢

转载自blog.csdn.net/a154555/article/details/126941692