教程:OAuth
OAuth 是一种开放的协议,旨在标准化桌面与网上应用程序访问用户个人数据的方式。OAuth 提供了一种机制,让用户授权访问私有数据,而不用共享它们的私有凭据(用户名/密码)。由于它的安全性以及存在一组标准库,许多网站已经开始启用 API 使用 OAuth。
这一教程将会引导您了解创建使用 OAuth 访问某个 API 的 Google Chrome 浏览器扩展程序的必要步骤,它提供了一个您可以在自己的扩展程序中重用的库。
这一教程使用 Google 文档列表数据 API 作为支持 OAuth 的 API 端点的例子。
要求
这一教程要求您具有编写 Google Chrome 浏览器扩展程序的一些经验,并且要求您对三方 OAuth 流程有一定的熟悉。尽管您不需要有 Google 文档列表数据 API(或者其他 Google 数据 API)的开发背景,但是理解这一协议可能有所帮助。
入门
首先,从位于 .../examples/extensions/oauth_contacts/ 的 Chromium 源代码树中将如下四个库文件复制到您的计算机上:
- chrome_ex_oauth.html - 用于重定向至 oauth_callback URL 的中间页面
- chrome_ex_oauth.js - 核心 OAuth 库
- chrome_ex_oauthsimple.js - 对 chrome_ex_oauth.js 有用的包装
- onload.js - 初始化 chrome_ex_oauth.html,如果需要开始 OAuth 流程则重定向网页
将这四个库文件放在您的扩展程序的根目录中(或者您的 JavaScript 代码存放的位置,然后在您的后台网页中按照以下顺序包含那两个 .js 文件:
<script type="text/javascript" src="chrome_ex_oauthsimple.js"></script> <script type="text/javascript" src="chrome_ex_oauth.js"></script> <script type="text/javascript" src="onload.js"></script>
您的后台网页将会管理 OAuth 流程。
扩展程序中的 OAuth 认证
如果您对 OAuth 协议比较熟悉,您能回想起来 OAuth 认证包括三个步骤:
- 获得初始的请求令牌
- 让用户为请求令牌授权
- 获得访问令牌
在扩展程序的环境中,这一流程遇到了一些问题。在服务提供商和应用之间无法建立使用者密钥/机密,在授权过程之后没有网上应用的 URL 让用户重定向。
幸运的是,Google 和另外几家公司正在开发用于已安装应用的 OAuth解决方案,这样您就可以从扩展程序的环境中使用。在已安装应用的 OAuth 认证过程中,使用者密钥/机密为'anonymous'/'anonymous',您还可以提供一个应用名称(而不是应用 URL),使用户授予访问权限。最终结果是一样的:您的后台页面请求初始令牌,打开新标签页进入授权页面,最后发出异步调用请求访问令牌。
设置代码
要初始化库,在后台网页中创建一个
ChromeExOAuth
对象:
var oauth = ChromeExOAuth.initBackgroundPage({ 'request_url': <OAuth 请求 URL>, 'authorize_url': <OAuth 认证 URL>, 'access_url': <OAuth 访问令牌 URL>, 'consumer_key': <OAuth 消费者密钥>, 'consumer_secret': <OAuth 消费者机密>, 'scope': <要访问的数据范围。并不是所有 OAuth 提供商都使用它>, 'app_name': <应用名称。并不是所有 OAuth 提供商都使用它> });
如果是文档列表 API 和 Google 的 OAuth 端点,初始化代码如下所示:
var oauth = ChromeExOAuth.initBackgroundPage({ 'request_url': 'https://www.google.com/accounts/OAuthGetRequestToken', 'authorize_url': 'https://www.google.com/accounts/OAuthAuthorizeToken', 'access_url': 'https://www.google.com/accounts/OAuthGetAccessToken', 'consumer_key': 'anonymous', 'consumer_secret': 'anonymous', 'scope': 'https://docs.google.com/feeds/', 'app_name': '我的 Google 文档扩展程序' });
要使用 OAuth 库,您必须在扩展程序的清单文件中声明 "tabs" 权限,您还必须声明您正在使用的网站,包括请求 URL、认证 URL、访问 URL,如果有必要的话还有区域 URL。例如:
"permissions": [ "tabs", "https://docs.google.com/feeds/*", "https://www.google.com/accounts/OAuthGetRequestToken", "https://www.google.com/accounts/OAuthAuthorizeToken", "https://www.google.com/accounts/OAuthGetAccessToken" ]
获取和认证请求令牌
一旦您设置好了后台网页后,就能调用
authorize()
函数,开始 OAuth
认证,使用户重定向至 OAuth
提供商。客户端库抽象了这一过程的大部分,所以您需要做的只是向
authorize()
函数传递一个回调函数,然后会打开一个新标签页,并重定向。
oauth.authorize(function() { // ... 准备获取个人数据... });
您不需要提供任何额外的逻辑来存储令牌和机密,因为该库已经在浏览器的
localStorage
中储存了这些值。如果库已经为当前作用域储存了访问令牌,则不用再打开新标签页。在任何一种情况下,都会调用回调函数。
发送已签名的 API 请求
一旦您指定的回调函数开始执行,就能调用
sendSignedRequest()
函数,向您的 API 发送已签名的请求。sendSignedRequest()
有三个参数:URI、回调函数和可选的参数对象。回调函数有两个参数:响应文本以及用来发出请求的
XMLHttpRequest
对象。
这一例子发送一个 HTTP GET
请求:
function callback(resp, xhr) { // ... 处理文本响应 ... }; function onAuthorized() { var url = 'https://docs.google.com/feeds/default/private/full'; var request = { 'method': 'GET', 'parameters': {'alt': 'json'} }; // 发送:GET https://docs.google.com/feeds/default/private/full?alt=json oauth.sendSignedRequest(url, callback, request); }; oauth.authorize(onAuthorized);
一个更复杂的例子使用 HTTP POST 请求,如下列代码所示:
function onAuthorized() { var url = 'https://docs.google.com/feeds/default/private/full'; var request = { 'method': 'POST', 'headers': { 'GData-Version': '3.0', 'Content-Type': 'application/atom+xml' }, 'parameters': { 'alt': 'json' }, 'body': '要发送的数据' }; // 发送:POST https://docs.google.com/feeds/default/private/full?alt=json oauth.sendSignedRequest(url, callback, request); };
默认情况下,sendSignedRequest()
函数在 URL 中(通过调用
oauth.signURL()
)发送 oauth_*
参数。如果您希望在 Authorization
头信息中发送
oauth_*
参数(或者需要直接访问已生成的头信息),请使用
getAuthorizationHeader()
。它的参数包括
URL、HTTP 方法以及可选的 URL 查询参数对象,表示为键/值对。
如下是上面所说内容的一个例子,使用
getAuthorizationHeader()
和一个
XMLHttpRequest
对象:
function stringify(parameters) { var params = []; for(var p in parameters) { params.push(encodeURIComponent(p) + '=' + encodeURIComponent(parameters[p])); } return params.join('&'); }; function onAuthorized() { var method = 'POST'; var url = 'https://docs.google.com/feeds/default/private/full'; var params = {'alt': 'json'}; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(data) { callback(xhr, data); }; xhr.open(method, url + '?' + stringify(params), true); xhr.setRequestHeader('GData-Version', '3.0'); xhr.setRequestHeader('Content-Type', 'application/atom+xml'); xhr.setRequestHeader('Authorization', oauth.getAuthorizationHeader(url, method, params)); xhr.send('Data to send'); };
示例代码
使用这些技术的示例扩展程序在 Chromium 源代码树的如下位置可用: