最近在做对用户的认证及REST API的访问权限控制,需要用OAuth来实现第三方应用对我们API的访问控制。OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth在全世界得到广泛应用,目前版本是2.0版。本文对OAuth 2.0的应用场景、设计思路和运行流程做一个简明通俗的解释。
上图是一个典型的应用场景,一个游戏应用希望读取用户Facebook账号的用户名和头像作为该用户在游戏中的角色信息,用户为了避免自己重新输入用户名并上传头像,必须让游戏应用读取自己Facebook账号的一些信息。但是只有得到用户授权,Facebook才会同意让游戏应用读取这些信息。如何让游戏应用获得用户授权呢?传统方法是用户把自己的Facebook账号用户名和密码告诉游戏应用,然后由游戏服务器代表用户登陆Facebook服务器获取用户的信息,但是这种方法存在一些严重的安全问题:
如何保证第三方应用能够安全可控的访问用户资源,这就是Oauth要解决的问题。
OAuth在第三方应用与服务提供商之间设置了一个授权层。第三方应用不能直接登录服务提供商,只能登录授权层,以此将用户与客户端区分开来。第三方应用登录授权层所用的令牌,与用户的密码不同。用户可以在登录授权的时候,指定授权层令牌的权限范围和有效期。
第三方应用登录授权层以后,服务提供商根据令牌的权限范围和有效期,向第三方应用开放用户资源。
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
上面六个步骤之中,B是关键,即用户怎样才能给予客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。
下面就介绍一下OAuth 2.0 的授权模式。
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式:
其中授权码模式是功能最完整、流程最严密的授权模式。它的特点是通过客户端的后台服务器,与服务提供商的认证服务器进行互动。
下面着重介绍授权码模式,其他模式可参考附件PPT。
上图是授权码模式的授权步骤:
(A)用户访问客户端后,客户端把用户导向认证服务器,认证服务器会返回一个授权页面,询问用户是否授权以及授权的资源
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器会返回一个重定向请求,将用户导向客户端在A步骤指定的"重定向URI",同时附上一个授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
下面是上面这些步骤所需要的参数和实例:
步骤A,用户访问客户端,客户端将用户导向认证服务器,包含以下参数:
下面是一个实例:
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
步骤B,用户在认证服务器登陆授权。
步骤C,假设用户给予授权,认证服务器将用户导向客户端事先指定的重定向URI,同时附上一个授权码。请求包含以下参数:
下面是一个实例:
HTTP/1.1
302 Found Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
步骤D,客户端收到授权码,附上“重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台服务器上完成,对用户不可见。请求包含以下参数:
下面是一个实例:
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
步骤E,认证服务器核对授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。认证服务器发送的HTTP回复包含以下参数:
下面是一个实例:
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"
}
从返回头信息可以看到,相关参数使用JSON格式发送(Content-Type: application/json)
。此外,HTTP头信息中明确指定不得缓存。token_type
表示令牌类型,该值大小写不敏感,必选项,可以是bearer
类型或mac
类型。
以上为授权码模式的详细授权过程,如果希望了解其他授权模式,请详见附件PPT。
OAuth 2.0 协议在设计时考虑了很多安全因素,下面介绍授权码模式的一些安全机制:
目前很多互联网公司都提供了自己的开放平台使第三方应用接入。开源项目中也有很多框架提供了OAuth的实现,例如Spring Security OAuth,Apache Oltu等。使用OAuth协议能够很好的保证第三方应用访问用户数据的安全性。
参考:理解 OAuth 2.0