OAuth 2.0
OAuth 2.0 简介
概述
OAuth 2.0 协议为用户资源的授权提供了一个安全、开放而又简易的标准,支持第三方服务访问有限的 HTTP 服务,通过在资源所有者和 HTTP 服务之间进行一个批准交互来代表资源者去访问这些资源,或者通过允许第三方应用程序以自己的名义获取访问权限。
通俗来说,OAuth 2.0 是一个第三方认证技术方案,最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。
为了方便理解,可以想象 OAuth2.0 就是在用户资源和第三方应用之间的一个中间层,它把资源和第三方应用隔开,使得第三方应用无法直接访问资源,从而起到保护资源的作用。为了访问这种受保护的资源,第三方应用(客户端)在访问的时候需要提供凭证,也就是需要告诉 OAuth2.0 你是谁你要做什么。你可以将用户名和密码告诉第三方应用,让第三方应用直接以你的名义去访问,也可以授权第三方应用去访问。
抽象的解释往往不得精髓,那么接下来我们通过在客户端使用微信登录,来进一步说明此协议相关概念。用户进入客户端(网站、小程序、APP等),通过客户端提供的微信登录方式,以微信账号登录此系统(用户是微信中个人信息资源的拥有者)
用户(资源拥有者)点击微信登录,页面响应微信登录二维码,用户通过扫描授权授权登录二维码,开始给客户端授权,扫描二维码之后,用户微信中会弹出授权操作,用户同意给客户端授权,微信会对资源拥有者的身份进行验证,验证通过后,微信会询问用户是否给授权网站访问自己的微信数据,用户点击"确认登录"表示同意授权,微信认证服务器会颁发一个授权码,并重定向到网站。
用户授权完成后,客户端获取到授权码,请求认证服务器申请令牌,此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。认证服务器接受到客户端请求后,认证服务器验证客户端请求的授权码,如果合法则给客户端颁发令牌(客户端访问资源的通行证),此交互过程用户看不到,当客户端拿到令牌后,用户在网站看到已经登录成功。用户登录成功后,客户端通过携带令牌请求资源服务器的用户资源,资源服务器验证令牌是否合法,如果合法则返回用户的基本信息。
授权第三方应用获取用户在微信服务的个人信息,其实就是 OAuth2.0 的作用。
角色
客户端:代表资源所有者并且经过所有者授权去访问受保护的资源的应用程序,本身不存储资源.需要通过资源拥有者的授权去请求资源服务器的资源,比如:Android客户端、Web客户、微信客户端等。
资源所有者:通常为用户,也可以是应用程序,即该资源的拥有者。
资源服务器:存储资源的服务器,比如,网站用户管理服务器存储了网站用户信息,网站相册服务器存储了用户的相册信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。
授权服务器:用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资源拥有者授权后方可访问。
常用术语
客户凭证(client Credentials):客户端的 ctientld 和密码用于认证客户。
令牌(tokens):授权服务器在接收到客户请求后,颁发的访问令牌,也是 OAuth 2.0 中最重要的东西。
作用域(scopes):客户请求访问令牌时,由资源拥有者额外指定的细分权限 (permission)
令牌类型
授秘码:仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌。
访问令牌:用于代表一个用户或服务直接去访问受保护的资源。
刷新令牌:用于去授权服务器获取一个刷新访问令牌。
BearerToken:不管谁拿到 Token 都可以访问资源.类似现金。
Proof of Possession(PoP)Token:可以校验 client 是否对 Token 有明确的拥有权。
特点
优点
- 更安全,客户端不接触用户密码,服务器端更易集中保护广泛传播并被持续采用
- 短寿命和封装的token
- 资源服务器和授权服务器解耦集中式授权,简化客户端
- HTTP/JSON友好,易于请求和传递token考虑多种客户端架构场景
- 客户可以具有不同的信任级别缺点
缺点
- 协议框架太境乏,造成各种实现的兼容性和互操作性差不是一个认证协议,本身并不能告诉你任何用户信息。
授权流程
抽象的 OAuth2.0 授权认证流程如图所示:
- (A):请求授权,客户端向资源所有者请求其授权。
- (B):授权许可,客户端收到资源所有者的请求并授权许可,这个授权许可是一个代表资源所有者授权的凭据。
- (C):请求令牌,客户端向授权服务器请求访问令牌,并出示授权许可。
- (D):令牌许可,授权服务器对客户端身份进行认证,并校验授权许可,如果都是有效的,则发放访问令牌。
- (E):请求资源,客户端向资源服务器请求受保护的资源,并出示访问令牌。
- (F):响应资源,资源服务器校验访问令牌,如果令牌有效,则提供服务。
OAuth 2.0 授权模式
授权码模式(Authorization Code Grant)
授权码模式是最复杂,同时也是使用最广泛的授权模式,授权码流程如图所示:
- (A):客户端通过将资源所有者的用户代理指向授权端点来启动这个流程。客户端包含它的客户端标识符,请求范围,本地状态,和重定向URI,在访问被允许(或者拒绝)后授权服务器立即将用户代理返回给重定向URI。
- (B):授权服务器验证资源所有者(通过用户代理),并确定资源所有者是否授予或拒绝客户端的访问请求。
- (C):假设资源所有者授权访问,那么授权服务器用之前提供的重定向URI(在请求中或在客户端时提供的)将用户代理重定向回客户端。重定向URI包括授权码和前面客户端提供的任意本地状态。
- (D):客户端用上一步接收到的授权码从授权服务器的令牌端点那里请求获取一个访问令牌。
- (E):授权服务器对客户端进行认证,校验授权码,并确保这个重定向URI和第三步(C)中那个URI匹配。如果校验通过,则发放访问令牌,以及可选的刷新令牌。
Authorization Request
客户端通过使用“application/x-www-form- urlencoding”格式向授权端点URI的查询组件添加以下参数来构造请求URI。
- response_type:响应类型必须是 code,必须携带。
- client_id:客户端标识,必须携带。
- redirect_uri:重定向 RUI,可选。
- scope:请求访问的范围,可选。
- state:一个不透明的值用于维护请求和回调之间的状态,授权服务器在将用户代理重定向会客户端的时候会带上该参数,可选的
例如:
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
Authorization Response
如果资源所有者授权访问请求,授权服务器发出授权代码并通过使用“application/x-www-form- urlencoding”格式向重定向URI的查询组件添加以下参数,将其给客户端。
- code:必须的。授权服务器生成的授权码。授权代码必须在发布后不久过期,以减少泄漏的风险。建议最大授权代码生命期为10分钟。客户端不得多次使用授权代码。如果授权代码不止一次使用,授权服务器必须拒绝请求,并在可能的情况下撤销先前基于该授权代码发布的所有令牌。授权代码是绑定到客户端标识符和重定向URI上的。
- state:如果之前客户端授权请求中带的有"state"参数,则响应的时候也会带上该参数。
例如:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
Access Token Request
客户端通过使用“application/ www-form-urlencoding”格式发送以下参数向令牌端点发出请求
- grant_type:必须的。值必须是"authorization_code"。
- code:必须的。值是从授权服务器那里接收的授权码。
- redirect_uri:如果在授权请求的时候包含"redirect_uri"参数,那么这里也需要包含"redirect_uri"参数。而且,这两处的"redirect_uri"必须完全相同。
- client_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 Response
例如:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
简化授权码模式(Implicit Grant)
隐式授权用于获取访问令牌(它不支持刷新令牌),它针对已知的操作特定重定向URI的公共客户端进行了优化。这些客户端通常在浏览器中使用脚本语言(如JavaScript)实现。
因为它是基于重定向的流程,所以客户端必须有能力和资源所有者的用户代理(典型地,是一个Web浏览器)进行交互,同时必须有能力接收来自授权服务器的重定向请求。
隐士授权类型不包含客户端身份验证,它依赖于资源所有者的存在和重定向URI的注册。由于访问令牌被编码到重定向URI中,所以它可能暴露给资源所有者以及同一台设备上的其它应用。
隐式授权流程如图所示:
- (A):客户端引导资源所有者的user-agent到授权端点。客户端携带它的客户端标识,请求scope,本地state和一个重定向URI。
- (B):授权服务器对资源所有者(通过user-agent)进行身份认证,并建立连接是否资源所有者允许或拒绝客户端的访问请求。
- (C):假设资源所有者允许访问,那么授权服务器通过重定向URI将user-agent返回客户端。
- (D):user-agent遵从重定向指令
- (E):web-hosted客户端资源返回一个web页面(典型的,内嵌脚本的HTML文档),并从片段中提取访问令牌。
- (F):user-agent执行web-hosted客户端提供的脚本,提取访问令牌
- (G):user-agent将访问令牌传给客户端
密码模式(Resource Owner Password Credentials Grant)
资源所有者密码凭证授予类型适用于资源所有者与客户端(如设备操作系统或高度特权应用程序)存在信任关系的情况。授权服务器在启用这种授予类型时应该特别小心,并且只在其他授权流程不可行的时候才允许使用。
这种授权类型适合于有能力维护资源所有者凭证(用户名和密码,典型地,用一个交互式的表单)的客户端。
资源所有者密码凭证流程如图:
- (A):资源所有者提供他的用户名和密码给客户端。
- (B):客户端携带从资源所有者那里收到的凭证去授权服务器的令牌端点那里请求获取访问令牌。
- (C):授权服务器对客户端进行身份认证,并校验资源所有者的凭证,如果都校验通过,则发放访问令牌。
客户端模式(Client Credentials Grant)
客户端用它自己的客户单凭证去请求获取访问令牌,客户端凭证授权流程如图所示:
- (A):客户端用授权服务器的认证,并请求获取访问令牌。
- (B):授权服务器验证客户端身份,如果严重通过,则发放令牌。
更新令牌
如果用户访问的时候,客户端的"访问令牌"已经过期,就是图中 E -> F 的过程,此时则需要使用"更新令牌"申请一个新的访问令牌,不需要再经过 A -> E 的过程,直接通过 G -> H 的步骤申请新令牌。
客户端发出更新令牌的 HTTP 请求,包含以下参数:
- granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。
- refresh_token:表示早前收到的更新令牌,必选项。
- scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。