123hjgSpring Cloud

理解OAuth2.0

2020-05-15  本文已影响0人  lotusgrm
前言

OAuth2.0 在实际工作中会经常接触到,尤其是做帐号系统的开发对这块应该更加的熟悉。常见的场景是:第三方登录。当你想要登录某个站点,但是没有帐号,而这个站点接入了如 wechat,QQ,Sina 等登录功能,我们使用 QQ 等第三方登录的过程就是使用的 OAuth2.0 协议。我所在的公司帐号系统也有自己独立的一套授权登录系统,但是发现在实际对接过程中很多人没有真正理解 OAuth2.0,下面我们来了解下 OAuth 协议的基本原理

OAuth 是一个关于 授权(authorization) 网络开放标准,在全世界范围内广泛应用,目前的版本是 2.0 版,下面这段话摘选自百度百科

OAuth2.0 是 OAuth 协议的延续版本,但不向前兼容 OAuth1.0(即完全废止了 OAuth1.0)。OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。2012 年 10 月,OAuth2.0 协议正式发布为 RFC 6749

本文对 OAuth2.0 的设计思路和运行流程,做一个简明通俗的解释

应用场景

为了加深一下 OAuth 的适用场景,下面我们举一个例子看下。
有一个 云冲印 的网站,可以将用户存储在 Google 的照片,冲印出来。用户要想使用该服务,必须让 云冲印 读取自己存储在 Google 上的照片。

bg2014051202.png
问题是只有得到用户的授权,Google 才会同意 云冲印 读取这些照片。那么,云冲印如何获取到用户的授权呢?
传统的方法是,用户将自己 Google 的帐号密码告诉 云冲印,后者就可以读取用户的照片了。但是这样的做法有几个严重的缺点。

OAuth 就是为了解决上面这些问题而诞生的

名词定义

在详细讲解 OAuth2.0 之前,需要了解几个专用名词。它对读懂后面的讲解,尤其是几张图,至关重要

从上面的这些名词中,不难理解,OAuth 的作用就是让 客户端 安全可控地获取 用户 授权,与 服务提供商 进行互动

OAuth 的思路

从上面的名词中,我们发现在 客户端服务提供商 之间,多了一层 授权层客户端 不能直接登录 服务提供商,只能登录授权层,以此将 客户端用户 区分开来。客户端 登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候指定授权层令牌的权限范围以及有效期
客户端 登录授权层以后,服务提供商 根据令牌的权限范围和有效期,向 客户端 开放用户存储的资源

运行流程

OAuth 2.0 的运行流程如下图,摘选自 RFC 6749


bg2014051203.png

从上面步骤中可以看出,B 是关键,即用户怎样才能给与客户端授权。有了这个授权后,客户端就可以向认证服务器申请令牌,获取令牌后进而凭借令牌获取资源服务器上的用户资源

下面我们来看下客户端获取授权的模式

客户端的授权模式

客户端必须得到用户的授权(authorization grant),才能进而获取令牌(token)。OAuth2.0 中定义了四种授权方式

授权码模式

授权码模式(authorization code)是功能最完整,流程最严密的授权模式。它的特点是通过客户端的后端服务器与 服务提供商 的认证服务器进行互动
图解

QQ20200512-193127@2x.png
QQ20200512-193247@2x.png
QQ20200512-193315@2x.png
QQ20200512-193342@2x.png
QQ20200512-193404@2x.png
QQ20200512-193429@2x.png
QQ20200512-193455@2x.png
QQ20200512-193522@2x.png
QQ20200512-193545@2x.png
QQ20200512-193607@2x.png
QQ20200512-193629@2x.png
QQ20200512-193652@2x.png

通过上面的图解,我们可以总结一下授权码模式的步骤:

下面的参数是上面整个流程中所需要的参数:

response_type:表示授权类型,必选项,此处的固定值为 code
client_id:表示客户端的 ID,必选项
redirect_uri:表示重定向 URI,可选项
scope:表示申请的权限范围,可选项
state:可以指定任意值,认证服务器会原封不动的返回这个值

关于 state 值以后再起一篇文章讲解,该参数是用于 oauth 授权过程的安全问题,可以防止 CSRF
下面看一个简易的例子

GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

服务端返回给客户端的 URI 包含以下参数:

code:授权码,必选项。该授权码有一个有效期,可由服务方自己设定,且该授权码只能使用一次,否则会被服务器拒绝。
state:认证服务器会原样返回该参数

下面是一个例子:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
          &state=xyz

在上面的步骤后第三方 APP 的后台服务器获取到了 code,开始向认证服务器发送申请令牌的 HTTP 请求,包含以下参数:

grant_type:表示使用的授权模式,必选项,此处的固定值为 authorization_code
code:表示上一步获得的授权码,必选项
redirect_uri:表示重定向 URI,必选项,且必须和上一步中的该参数表示一致
client_id:表示客户端 ID,必选项

下面是一个例子:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

认证服务器返回的数据中包含以下参数:

access_token:表示访问令牌,必选项
expires_in:表示过期时间,单位为秒
refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项
sope:表示权限范围,如果与客户端申请的范围一致,此项可省略

下面是一个例子:

HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

更新令牌
如果用户访问的时候,旧的令牌已经过期,则需要使用 更新令牌 申请一个新的访问令牌
第三方 APP 的后台服务器发出的 HTTP 请求,包含以下参数:

granttype:表示使用的授权模式,此处的值固定位 *refreshtoken* ,必选项
refresh_token:表示早期收到的更新令牌,必选项
scope:表示申请的权限范围,不可以超出上一次申请的范围,如果该参数省略,则表示与上一次保持一致

下面是一个例子:

POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

参考文章:https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

上一篇 下一篇

猜你喜欢

热点阅读