对比授权机制,你更想用哪种?

开发 前端
是不是曾经某培训机构教授的 SSO 单点登录的,是的没错,而这种 SSO 的单点登录在当年的培训机构中,使用的就是 Session 共享,也就是用 Redis 做中间模拟 Session ,但是授权机制真的有这么简单么?

[[411611]]

本文转载自微信公众号「Java极客技术」,作者鸭血粉丝。转载本文请联系Java极客技术公众号。

授权机制,当我们说到这个问题的时候,大家对它的第一印象是在哪个地方呢?是不是曾经某培训机构教授的 SSO 单点登录的,是的没错,而这种 SSO 的单点登录在当年的培训机构中,使用的就是 Session 共享,也就是用 Redis 做中间模拟 Session ,但是授权机制真的有这么简单么?接下来阿粉就来强势对比一下关于授权机制了。

Cookie-Session 认证授权

Cookie-Session 认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。

但是这时候我们就得考虑一下 Cookie 的存活时间了,当我们关闭浏览器的时候,Cookie就会被删除,就算我们调整了 Cookie 的存活时间,但是他依然有很大的弊端,Cookie 是很容易被拦截到的,阿粉之前就看到过某个知名的 OA 系统,就曾经把用户的ID 放到了 Cookie 中,只不过是把 Cookie 里面的键给设置成了 imageUrl,但是实际上这种,看着有点搞人的意思,图片地址是一堆长的字符串,你在前端拦截到之后, 明眼人一眼就能知道这种肯定不是图片路径,而且当我们使用 Cookie 进行用户识别,用户就会很容易受到跨站请求伪造的攻击,也就是我们经常说的 CSRF .

JWT

既然在这里对比 JWT ,我们就得先知道 JWT 是个什么东西,JSON Web Token (JWT) 实际上用大白话说,它就是一种认证机制,让后台知道请求是来自于受信的客户端。

技术都是随着问题出现的,只要有问题,那么很快就会有解决这个问题的技术出现,同样,JWT 出现的只不过比较早而已,因为现在微服务,分布式横行遍布,不管是大公司,还是小公司,很多都开始做分布式的项目,这做分布式也不仅仅是停留在了只存在大公司了,既然选择使用了分布式,那么各种各样的问题就来了。

  • 跨域身份验证
  • 分布式session共享
  • 分布式站点的单点登录

JWT 是个什么玩意

我们先看一下官方网站给的内容,What is JSON Web Token?

  1. JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA 

JSON Web令牌(JWT)是一种开放标准(RFC7519),它定义了一种紧凑且独立的方式,用于在各方之间安全地作为JSON对象传输信息。由于该信息是数字签名的,因此可以验证和信任此信息。可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对对对对JWTs进行签名.

阿粉就直接用百度翻译了,结果翻译出来竟然差不多,看来百度翻译有时候也没有那么差劲。

那么什么时候需要去使用 JWT 呢?

在官网中,给出了两种情况下去使用 JWT ,Authorization 和 Information Exchange,一种是授权,授权我们都懂,就是当用户登录后,每个后续请求都将包括JWT,允许用户访问该令牌允许的路由、服务和资源,而资源交换,实际上简单的说,就是在数据传输中用 JWT 令牌在安全地在各方之间传输信息

那么我们既然知道了什么时候来使用 JWT, 我们就来看看 JWT 到底是长成什么样子,

JWT 构成:

  • Header 头部
  • Payload 有效载荷
  • Signature 签名

我们从官网上获取了一段的内容,然后逐个来看,

  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c 

既然它说 JWT 是由三段信息构成的,而这三段信息,是用 .来进行隔开的,也就是上面这长串的字符串,

Header 头部,我们看到图里面也给出了,Header 中存储的实际上就是2部分的内容。typ:类型 alg:加密算法,

然后他是对头部进行的 Base64 加密,我就是我们在官网摘下来的第一段的内容,就出现了加密字符串 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 。

Payload 有效载荷

实际上有效载荷实际上就是存储有效信息的地方,那么他都存储了一些什么内容呢?

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间

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

为什么会有这么多,因为在 JWT 的规范中,他告诉我们的是,建议但不强制使用,也就是说,你可以根据自身的应用去选择使用,比如官网给出的,他就没有写全面,就使用了三个:

  1.   "sub""1234567890"
  2.   "name""John Doe"
  3.   "iat": 1516239022 

而实际上这部分的内容却是比较重要的内容。

signature签名信息

实际上这个就是一个组装起来的,将头部和载荷用’.'号连接,再加上一串密钥,经过头部声明的加密算法加密后得到签名。

这个 Header 和 Payload 都是加密过的,而在这个地方它还进行了 “加盐” 的操作,将这三部分用.连接成一个完整的字符串,构成了最终的jwt

jwt其实并不是什么高深莫测的技术,在很多技术人的眼中,可能觉得他会非常的low ,实际上虽然不高端,但是也没有那么 low,认证服务器通过对称或非对称的加密方式利用payload生成signature,并在header中申明签名方式,这就是 JWT 的本质实现方式。

JWT 的有点其实很明显,

  • 通过验证签名的方式可以直接在资源服务器本地完成授权校验
  • 在payload中可以包含用户相关信息,实现了token和用户信息的绑定

使用场景一般是用在一次性的身份验证上,千万不要想着去用 JWT 去代替 Session,虽然 JWT 可以设置失效时间,但是在有效期内,它是无法作废的。

OAuth2认证

OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者。资源所有者同意以后,资源服务器可以向客户端颁发令牌。客户端通过令牌,去请求数据。

其实这个 OAuth 的核心就是向第三方应用颁发令牌,而在 Oauth2 中定义了四种获得令牌的流程,也就是通俗的四种授权方式,但是我们经常使用的也就是那么一种。

  • 授权码
  • 隐藏式(简化)
  • 密码式
  • 客户端凭证
  • 授权码模式

这是在 Oauth 里面的功能算是最完整的,而且流程最严密的授权模式。

授权码模式的步骤:

  • 1.用户访问客户端,后者将前者导向认证服务器
  • 2.用户选择是否给予客户端授权
  • 3.假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码
  • 4.客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见
  • 5.认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)

其实授权码模式就相当于是第三方的应用去先申请一个授权码,然后再用该授权码获取令牌。

总结下来就是四个步骤 :

1:请求授权码

2:返回授权码

3:请求令牌

4:返回令牌

我们给出一个例子,然后分析一下。

  1. https://2.com/oauth/authorize? //授权地址 
  2.   response_type=code& //参数1:response_type :这里表示授权的类型,此处的值固定为"code" 
  3.   client_id=CLIENT_ID& //参数2:client_id :表示客户端的ID 
  4.   redirect_uri=CALLBACK_URL& //参数3:redirect_uri :表示重定向URL 
  5.   scope=read //参数4:scope: 表示申请的权限范围 
  6.    

上面的地址,就相当于第一步,携带所需要的参数请求 网站2,请求获取授权码。

  1. https://1.com/callback?code=AUTHORIZATION_CODE //code 授权码 

上面的地址就是第二步了,网站2给网站1返回授权码,

  1. https://2.com/oauth/token? 
  2.  client_id=CLIENT_ID&   客户端ID 
  3.  client_secret=CLIENT_SECRET& 客户端密钥 
  4.  grant_type=authorization_code& 使用的授权模式 authorization_code :授权码模式 
  5.  code=AUTHORIZATION_CODE& 授权码 
  6.  redirect_uri=CALLBACK_URL  表示重定向URL 

上面的地址就到第三步了,用授权码去索要令牌的请求就发送了。

请求发送完成后,2网站收到请求之后,这时候就向 重定向URL 发送以下的 JSON 数据,

  1. {     
  2.   "access_token":"ACCESS_TOKEN", //访问令牌 
  3.   "token_type":"bearer",// 令牌类型 
  4.   "expires_in":2592000, // 过期时间 
  5.   "refresh_token":"REFRESH_TOKEN", // 更新令牌 
  6.   "scope":"read", // 权限范围 只读 
  7.   "uid":100101, // 
  8.   "info":{...} // 

这时候 访问令牌 我们就要有了,这完成所有的步骤后,我们就拿到了我们访问的令牌了,也就是我们完成了所需要的授权了。

隐藏式

其实隐藏式就是简化版的授权模式,他省略了获取 授权码 的过程,而是直接请求获取 令牌 的过程。

案例如下:

  1. https://2.com/oauth/authorize? 
  2.   response_type=token& 授权的类型,此处的值固定为"token" 
  3.   client_id=CLIENT_ID&  客户端ID 
  4.   redirect_uri=CALLBACK_URL& 表示重定向URL 
  5.   scope=read  权限范围 只读 

上面授权类型直接就是索要令牌,

第二步也很简单,就是直接给你返回你需要的令牌

  1. https://1.com/callback#token=ACCESS_TOKEN 

上面的 Token 就是我们需要的令牌了,

密码式

这种为什么称之为 密码式 ,是因为它在请求的时候,是用密码去换令牌,这就需要一个前提,你对这个网站有高度的信用度,如果你不信用他,他给你账号密码作用都不大,给了你也不会授权给它 Token 不是么。

案例步骤如下:

1.请求令牌

  1. https://oauth.2.com/token? 
  2.   grant_type=password& 授权方式:指定为密码式 
  3.   username=USERNAME&  用户名 
  4.   password=PASSWORD&  密码 
  5.   client_id=CLIENT_ID  客户端ID 
  6.    

2.返回令牌

  1. https://1.com/callback#token=ACCESS_TOKEN 

这个感觉和隐藏式差距不大,一个是直接要,一个是拿着参数要。

凭证式

这个凭证式的步骤也是比较少的,实际上阿粉感觉这种方式不知道算不算是授权的方式,因为这种模式是客户端以自己的名义向"授权服务提供者"进行认证,但是既然说是,那就暂且的认定他是,

1:请求令牌

  1. https://oauth.2.com/token? 
  2.   grant_type=client_credentials&  授权方式:凭证式 
  3.   client_id=CLIENT_ID&   客户端ID 
  4.   client_secret=CLIENT_SECRET 客户端密钥 

2.返回令牌

  1. https://1.com/callback#token=ACCESS_TOKEN 

这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,也就是说可能出现多个用户共享同一个令牌。

为什么要比较 JWT 和Oauth2 ,因为很多不明所以的人总是会在挑选技术的时候,会把二者拿出来对比,其实上,他们两个没有可比性,因为 JWT 是用于发布接入令牌,并对发布的签名接入令牌进行验证的方法。

OAuth2是一种授权框架,授权第三方应用访问特定资源。

也就是说:

  • OAuth2用在使用第三方账号登录的情况
  • JWT是用在前后端分离, 需要简单的对后台API进行保护

所以你知道怎么选择了么?

文章参考

 

《阮一峰的网络日志》 《JWT官方文档》

 

责任编辑:武晓燕 来源: Java极客技术
相关推荐

2019-04-24 08:34:46

编程语言PythonJava

2023-08-08 10:19:53

文档标记语言

2022-04-21 09:00:00

API安全密钥

2021-12-21 08:05:19

AI基础计算机

2015-10-28 14:29:12

软件定义存储软件定义技术

2015-06-08 14:17:41

云容灾DR云托管

2021-04-27 09:00:00

PythonIDE开发

2016-01-26 09:58:28

云存储云服务云安全

2012-07-03 11:13:07

2020-12-09 18:36:28

ObjectArrayJavaSc

2024-04-24 12:03:20

2020-04-08 15:59:23

显卡Linux命令

2013-07-23 15:11:41

流行编程风格

2021-11-28 17:26:50

PyTorchJuliaPython

2022-08-18 09:51:50

Python代码循环

2020-10-27 15:01:25

编程语言PythonJava

2021-12-13 08:29:18

Code编程字体

2019-03-12 18:33:57

树莓派Linux

2024-01-31 09:24:58

2023-04-10 07:40:36

GraphQLRest通信模式
点赞
收藏

51CTO技术栈公众号