OAuth 2.0 认证框架(一)

最近需要搭一个第三方验证的服务器。这个想法之前就有,但是当时水平粗浅,也只能看个一知半解,没有理解透彻。趁这个机会好好学一学 OAuth 2.0 认证框架。

一些小问题

什么是 OAuth 2.0

OAuth 是一套第三方认证框架,即认证服务器和资源服务器分开,用户向认证服务器授权,资源服务器才有权使用认证服务器认证用户身份,认证通过后用户才有权使用资源服务器中的权限资源。2.0 是目前的版本号。
以下的 OAuth 代指 OAuth 2.0 框架。
目前微信、QQ、新浪微博、人人网等众多网站都支持这样的第三方登录,基本都是使用的 OAuth 框架。其中 Github 的较为标准。所以我们可以以此为例。

为什么要用第三方登录

对于小型应用而言,希望降低使用者的门槛,无需经过复杂的注册;另一方面可以直接使用腾讯、新浪等大网站的客户资源;性能和成本上讲也省掉了自己维护大量用户数据的烦恼。
对于大型网站而言,方便自己解耦,可以更方便地扩展新的应用;也可以吸引用户粘性,让用户更多的应用关联自己的用户资源;同时这种关联信息也是日后数据挖掘的一项原料。
当然,上面的这些其实都是我瞎猜的。

自己的项目之所以要将授权服务器拆开纯粹是为了解耦,可以多应用使用相同的用户资源而不会建立多余数据库连接。

OAuth 基本定义

角色

OAuth 框架定义了四种角色:

  • 资源拥有者(Resource Owner)
    • 指权限资源的拥有者,当拥有者是一个人的时候,我们称为用户。(权限资源指需要经过验证,确认具有权限的主体才能获取的资源)
  • 资源服务器(Resource Server)
    • 管理权限资源,接受和响应使用令牌(token)的请求。
  • 客户端(Client)
    • 经过资源拥有者授权的、代表其发送权限资源请求的应用。(客户端可以泡在服务器、用户电脑或是其它任何设备上)
  • 授权服务器(Authorization Server)
    • 在验证资源拥有者身份和获得授权后向客户端分配令牌(token)。

协议流

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+

(A) Authorization Request

客户端需要资源拥有者授权。授权请求可以直接对资源拥有者请求,或者更好的做法是通过授权服务器作为媒介。

(B) Authorization Grant

客户端收到来自资源拥有者的授权许可。许可的格式通常使用以下定义的四种授权模式的一种(当然你也可以自行定义授权模式)。具体使用何种模式取决于客户端使用了哪种且授权服务器是否支持。

(C) Authorization Grant

客户端向授权服务器请求一个令牌(token)表示授权许可。

(D) Access Token

授权服务器验证客户端并确认授权许可。如果授权许可通过,那么分配给客户端一个 token。

(E) Access Token

客户端通过 token 验证身份并从资源服务器请求资源。

(F) Protected Resource

资源服务器验证 token 有效性后处理请求。

授权模式

有四种常见的授权模式:

授权码模式

这种授权模式将授权服务器作为客户端和资源拥有者的中间媒介。用户不向客户端直接授权,而是将用户指引到授权服务器,然后将得到授权码的用户定向回客户端(原文 1.3.1 中提到通过 user-agent 的方式引导,我没有太懂是什么意思,欢迎看懂的小伙伴给我解答一下)

简化模式

简化模式是为使用脚本语言(例如 JavaScript)的客户端优化设计的一种授权模式。简化模式中不分配授权码,而是直接分配 token(作为资源拥有者的身份验证结果)。因为没有中间验证信息(例如授权码),所以这种授权模式称为简化模式。
在简化模式中,授权服务器并不验证客户端就直接分配了 token。在一些情况下,客户端身份可以通过重定向到返回 token 的 URI 来验证客户端。这个 token 可能会被暴露给用户或者其他用户 UA 层面的应用。
简化模式对于一些比如浏览器客户端可以提高效率,当然也会导致一些安全上的问题。

第一点是可能 token 被抓,所以必须使用 TLS(即使用 HTTPS)。
第二点是可能存在“点击挟持”(clickjacking),即使用隐形的不可见的 button 覆盖在授权页面上,让用户在不知情情况下误授权。所以本地应用应当使用外部浏览器而不是应用内的嵌入浏览器。

密码验证模式

密码模式即直接使用账号密码(或其他验证信息)登录。只应当用于用户对客户端高度信任(例如是设备操作系统的一部分)且其他授权模式都不可用的情况。
即使使用这种模式,客户端也不应当存储账号密码,而是每次都使用验证信息去交换 token。

客户端证书模式

将客户端证书(或其他形式的客户端凭证)看做授权凭证。在已经授权的资源范围内,客户端可以被看做用户本人,拥有获取权限资源的权限。

授权令牌(token)

简单来说,token 就是表示授权的一个临时证明,通常是一个字符串。这个字符串通常对客户端是不透明(opaque)的(根据我的理解,应该指的是看不见)。用户授权后,资源服务器和授权服务器才可以通过 token 来验证对某一指定域的权限。当超越已授权的权限时,可能需要提供额外的验证信息来获得权限。
token 本身就已经足够表明授权者身份。

参考文献

The OAuth 2.0 Authorization Framework - Internet Engineering Task Force (IETF)