理解OAuth2.0

前言

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 的帐号密码告诉 云冲印,后者就可以读取用户的照片了。但是这样的做法有几个严重的缺点。

  • 帐号密码告诉云冲印,这样有可能会造成帐号密码泄露,很不安全
  • 云冲印 拥有了获取用户存储在 Google 所有资料的权利,用户没办法限制 云冲印 获得授权的范围和有效期
  • 用户只能通过修改密码,才能收回赋予 云冲印 的权利。但是这样做,会使得其他所有获得用户授权的第三方应用全部失效
  • 只要有一个第三方应用程序被破解,就会导致用户密码泄露,以及所有被密码保护的数据泄露

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

名词定义

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

  • Third-party application:第三方应用程序,本文中又称 客户端,即上面例子中的 云冲印
  • HTTP service:HTTP 服务提供商,本文中简称 服务提供商,即上面例子中的 Google
  • Resource owner:资源所有者,本文中又称 用户
  • User Agent:用户代理,本文中指浏览器
  • Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器
  • Resource server:资源服务器,即服务提供商存放用户资源的服务器。它和认证服务器可以是同一台服务器,也可以是不同服务器

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

OAuth 的思路

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

运行流程

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


bg2014051203.png
  • (A) 用户打开客户端后,客户端要求用户给予授权
  • (B) 用户同意授权给客户端
  • (C) 客户端使用上一步获得的授权,向认证服务器申请令牌
  • (D) 认证服务器对客户端进行认证后,确认无误,同意发放令牌
  • (E) 客户端使用令牌,向资源服务器申请获取资源
  • (F) 资源服务器确认令牌无误后,同意向客户端开放资源

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

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

客户端的授权模式

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

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)
    在上述四种模式中最常用的是 授权码模式(authorization code),我们熟悉的微博,QQ等都是这种模式,本篇文章中我们只介绍这种模式
授权码模式

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












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

  • 用户访问第三方 APP,后者询问是否允许访问用户的第三方帐号,在得到用户允许后第三方 APP 向认证服务器发送一个授权请求
  • 认证服务器校验第三方的请求合法后,认证服务器将用户导向第三方 APP 事先指定的 重定向URI ,同时附上一个授权码
  • 第三方 APP 收到授权码之后,附上事前已经定好的 重定向URI,向认证服务器申请令牌。这一步是在第三方的后台服务器上完成的,对用户不可见
  • 认证服务器在校验了授权码和重定向URI 的合法性,确认无误后,向客户端发送令牌(Access Token)

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

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

你可能感兴趣的:(理解OAuth2.0)