本文档介绍了如何从 Flash 或 Silverlight 应用中使用 Google 的 AuthSub 身份验证系统。
注意:如果您已熟悉 AuthSub(Google 针对基于 Web 的应用的账号身份验证服务),您会发现 ActionScript 版 AuthSub 在概念上非常相似。底层实现有所不同,但作为客户端应用开发者,您无需关注这些差异。在某些文档中,如果区分无关紧要,我们会将 ActionScript 版 AuthSub 简称为“AuthSub”。
借助适用于 ActionScript 的 AuthSub 接口,Flash 或 Silverlight 应用可以代表用户向受保护的 Google Data API Feed 进行身份验证。为了保持高安全级别,该接口使应用能够获取身份验证令牌,而无需处理用户的账号登录信息。
适用于 ActionScript 的 AuthSub 是适用于 JavaScript 的 AuthSub 的变体。与 JavaScript 的 AuthSub 类似,它提供了一种跨网域方法,供客户端应用从托管在非 Google 网域上的网页进行身份验证。它与标准 AuthSub 的不同之处在于,身份验证服务位于不同的网域(accounts.googleapis.com 而不是 www.google.com),并提供一个 crossdomain.xml 文件,允许从外部网站访问该网域。
如需了解如何使用所有身份验证服务 API,另请参阅 Google Accounts API Group。
受众群体
本文档面向正在开发访问 Google 服务的 Flash 或 Silverlight Web 应用的程序员。
本文档假定您了解 Google Data API 协议和 AuthSub 接口背后的基本原理。本文还假定您已了解如何使用 ActionScript 进行编程。
受支持的环境
目前,Firefox 1.5 及更高版本和 Internet Explorer 6.0 及更高版本支持 ActionScript 的 AuthSub,但需要安装 Flash 9.0 及更高版本或 Silverlight 2.0 及更高版本。
ActionScript 版 AuthSub 的工作原理
下面简要介绍了 Web 应用、Google 身份验证服务和 Google 数据服务之间的通信方式:
- 若要代表用户访问 Google Data 服务,Web 应用必须具有有效的身份验证令牌。通常,应用会将此令牌存储在 Cookie 中;如果不存在此类 Cookie,Web 应用必须通过 AuthSub 获取令牌。为了获取令牌,Web 应用会向身份验证服务发出 AuthSub for ActionScript 登录调用,并指定要访问的服务。
- 在收到来自 Web 应用的请求后,身份验证服务会将用户重定向到“访问权限申请”页面。此页面会提示用户登录其 Google 账号,并要求用户授予或拒绝访问其 Google 服务的权限。
- 用户决定是否授予对 Web 应用的访问权限。 如果用户拒绝授予访问权限,系统会将用户定向到 Google 页面,而不是返回到 Web 应用。
- 如果用户成功登录并授予访问权限,身份验证服务会将用户重定向回发出原始调用的 Web 应用网址。重定向通过查询参数为指定服务提供身份验证令牌。应用应将令牌作为 Cookie 存储在用户浏览器中,位于 Web 应用的网域下。令牌在被撤消之前一直有效。(如需有关何时撤消令牌的建议,请参阅关于令牌部分。)
- Web 应用会与 Google Data 服务联系,并随发送给该服务的每个请求一起发送身份验证令牌。
- 如果 Google Data 服务识别出该令牌,就会提供所请求的数据。
使用 ActionScript 接口的 AuthSub
AuthSub for ActionScript(简称 AuthSubAS)为使用 Google Data API 的 Flash(或 Silverlight)应用提供跨网域的 AuthSub 端点。
AuthSubAS 提供 google.com 上 AuthSub 端点的镜像,并附带一个额外的 crossdomain.xml 文件,允许 Flash(或 Silverlight)访问这些端点。例如,可以通过访问 https://accounts.googleapis.com/accounts/AuthSubSessionToken 来使用 AuthSubSessionToken 端点。
以下步骤详细介绍了如何获取身份验证令牌并使用该令牌从 Flash 应用访问 Google 服务。
- 设置跨网域政策。
如需以跨网域方式使用 Flash,必须为要访问的每个外部网域初始化一个政策。为此,请针对每个网域调用 ActionScript 方法
Security.loadPolicyFile(policy),如下所示:<?xml version="1.0" encoding="utf-8"?> <Application xmlns="http://www.adobe.com/2006/mxml" initialize="onInitialized()" applicationComplete="onLoaded()"> <Script> import flash.external.ExternalInterface; import flash.net.navigateToURL; import mx.controls.Alert; private function onInitialized() : void { // Load the cross domain policy file for each of the googleapis.com // domains used. At the very least, we need the ones for the API (photos, // in this case) and the one for AuthSub for ActionScript (accounts). Security.loadPolicyFile('http://photos.googleapis.com/data/crossdomain.xml'); Security.loadPolicyFile('https://accounts.googleapis.com/crossdomain.xml'); }
请注意,这里我们加载了
accounts.googleapis.com(AuthSubAS) 和photos.googleapis.com/data(示例稍后会访问 PicasaWeb)的政策。 - 请求一次性令牌。
AuthSub 流程的第一步是从 AuthSub 端点请求一次性令牌。您的应用应通过调用
AuthSubRequest端点来执行此操作,如下所示:var getTokenPage : URLRequest = new URLRequest('https://www.google.com/accounts/AuthSubRequest'); // Construct the parameters of the AuthSub request. These are the same parameters // as normal AuthSub, which can be found here: /accounts/docs/AuthSub.html#AuthSubRequest var authSubParams : URLVariables = new URLVariables(); authSubParams['scope'] = 'http://photos.googleapis.com/data'; // photos API authSubParams['session'] = 1; // single-use token authSubParams['secure'] = 0; // non-secure apps authSubParams['next'] = 'photos.swf'; // The URL of this app. getTokenPage.data = authSubParams; navigateToURL(getTokenPage, '_top');
此方法需要 scope 值。每项 Google 服务都会定义其允许的访问权限范围,您需要在令牌请求中引用该范围。如需确定要使用的范围值,请查看您要访问的 Google 服务的文档。范围看起来像一个网址;它可以是标识服务的简单网址,也可以指定更严格的访问权限,例如将访问权限限制为只读。如果服务提供多种范围选择,请请求范围尽可能小的令牌。例如,如需访问 Google 日历的数据 Feed,请使用
'http://www.google.com/calendar/feeds'范围,而不是'http://www.google.com/calendar'。提示:
- 我们强烈建议您提供登录按钮或其他用户输入机制,以提示用户手动开始登录流程。如果您在加载后立即检查并重定向,而不等待用户互动,那么用户到达您的网页后首先看到的是 Google 登录页面。如果用户决定不登录,Google 就不会将他们重定向回您的网页;因此,从用户的角度来看,他们尝试访问您的网页,但被发送到其他网页,并且再也没有被发送回来。这种情况可能会让用户感到困惑和沮丧。
- 需要访问用户的多项 Google 服务的应用必须为每项新服务请求一个新令牌(因为每项服务的范围都不同)。
- 请求身份验证令牌。
AuthSubRequest端点会将用户浏览器的网址设置为http://yourWebAppUrl?token=singleUseToken,从而向您的应用返回一次性令牌。应用收到一次性令牌后,必须将该令牌换成可多次使用(长期有效)的令牌,然后才能使用该令牌针对 Google 数据 Feed 发出请求。为此,请使用一次性令牌调用AuthSubSessionToken方法。应用在加载时应检查网址中是否存在
token参数:private function onLoaded() : void { // Once the application has loaded, check to see if an AuthSub token was
// placed into the current page's URL. If it was, the user has already
// authenticated, and we can continue to connect to the the service itself. var searchPortion : String = ExternalInterface.call('window.location.search.toString'); if (searchPortion.length > 0) { // remove the ? from the token and extract the token. searchPortion = searchPortion.substring(1); // NOTE: Real applications should parse the URL properly. if (searchPortion.indexOf('token=') == 0) { getLongLivedToken(searchPortion.substring(6)); return; } // more code ... }如果找到令牌,则应调用类似
getLongLivedToken的方法,该方法会调用AuthSubSessionToken端点:private function getLongLivedToken(singleUseToken : String) : void { // Construct a call to the AuthSub for ActionScript endpoint on accounts.googleapis.com. // This call will exchange the single use token given to use by AuthSub for a long-term // token that we can use to make requests to endpoints such as Photos. var getTokenRequest : URLRequest = new URLRequest('https://accounts.googleapis.com/accounts/AuthSubSessionToken'); // Due to a bug in Flash, a URLRequest with a GET request will // not properly send headers. We therefore use POST for this and *ALL* // requests. getTokenRequest.method = URLRequestMethod.POST; // Due to a bug in Flash, a URLRequest without a valid parameter will // not properly send headers. We therefore add a useless parameter to // make this code work. getTokenRequest.data = new URLVariables('pleaseignore=ignore'); // Add the AuthSub for ActionScript headers. getTokenRequest.requestHeaders.push(new URLRequestHeader('Authorization', 'AuthSub token="' + singleUseToken + '"')); // Create the loader to get the token itself. The loader will callback // to the following event handlers if and when the server responds. var getToken : URLLoader = new URLLoader(); getToken.addEventListener(Event.COMPLETE, onGetTokenResult); getToken.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetTokenFailed); getToken.addEventListener(IOErrorEvent.IO_ERROR, onGetTokenFailed); try { getToken.load(getTokenRequest); } catch (e : Error) { Alert.show('Some error occurred: ' + e); }
类似
onGetTokenResult处理程序的方法应保存返回的令牌:private function onGetTokenResult(e : Event) : void { // Load the parameters from the response. var getToken : URLLoader = URLLoader(e.target); var params : URLVariables = new URLVariables(getToken.data); // Parse the session token from the result. Real applications // might at this point store the token in a long-term cookie so // that repeated usages of the application do not require this entire // authentication process. sessionToken = params.Token; // Trim the newline from the end of the session token. sessionToken = sessionToken.substring(0, sessionToken.length - 1); }
提示:
- 我们强烈建议您的应用将长期令牌存储在 Cookie 中,并在检查短期令牌之前检查这些令牌;这样可以防止用户每次想使用您的应用时都必须访问 AuthSub 确认页面。
- 使用身份验证令牌。
如需使用身份验证令牌,请通过
Authorization标头将其附加到向 Google 服务发出的任何请求中:Authorization: AuthSub token="(session token goes here)"
适用于 Photos 服务的 ActionScript 示例:
// Prepare a request to the photos API for the private album // of the user. var albumRequest : URLRequest = new URLRequest('http://photos.googleapis.com/data/feed/api/user/default'); albumRequest.data = new URLVariables('access=private&v=2&err=xml'); // Due to a bug in Flash, a URLRequest with a GET request will // not properly send headers. We therefore use POST for this and *ALL* // requests. albumRequest.method = URLRequestMethod.POST; var authsubHeader : String = 'AuthSub token="' + sessionToken + '"'; // Add the Authorization header which uses the session token. albumRequest.requestHeaders.push(new URLRequestHeader('Authorization', authsubHeader)); // The X-HTTP-Method-Override header tells the Photos API to treat this request // as a GET request, even though it is being conducted as a POST (due to the bug // mentioned above). This is very important, as GData APIs will react differently // to different HTTP request types. albumRequest.requestHeaders.push(new URLRequestHeader('X-HTTP-Method-Override', 'GET')); // We expect ATOM XML to be returned. albumRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'application/atom+xml'));
Google 建议提供手动退出功能,例如退出按钮或可点击的链接。这种方法让用户可以选择随时退出,也可以选择保持登录状态,以便下次访问您的应用时可以方便地查看数据 Feed。
令牌简介
本部分介绍了 AuthSub 为 ActionScript 使用的令牌。在大多数情况下,您无需了解此信息。
每个身份验证令牌都特定于以下数据:
- Google 服务范围
- 用户的 Google 账号
- 客户端应用
令牌数据可确保只有指定的第三方应用可以请求数据,并且请求仅限于指定范围和用户账号中的数据。
对于范围、用户和客户端的这种组合,一次只能有一个令牌有效。Web 应用每次需要访问特定用户的新 Google 服务时,都必须请求新令牌。令牌涵盖的访问权限范围取决于 Google 服务,该服务可以选择限制对特定类型的数据或活动的访问权限,例如只读访问权限。
AuthSub 为 ActionScript 接口返回的令牌可以根据需要多次使用,直到被撤消为止。令牌的生命周期由应用自行管理,需要在安全性和便利性之间取得平衡。Google 建议您在每次启动新会话时都请求新令牌。
某些 Google 服务可能仅允许已注册并使用安全令牌的 Web 应用访问。此类服务不支持 ActionScript 的 AuthSub。若要使用安全令牌,贵组织必须向 Google 注册 SSL 证书,并对这些数据源的所有请求进行签名。