本文档介绍了如何通过 Flash 或 Silverlight 应用使用 Google 的 AuthSub 身份验证系统。
注意:如果您已熟悉 AuthSub(Google 的适用于 Web 应用的帐号身份验证服务),就会发现 AuthSub for Action 在概念上非常相似。底层实现是不同的,但区别对客户端应用开发者而言并不重要。在某些文档中,由于区分不相关,我们用适用于 AuthSub 的 Action 简称为“AuthSub”。
AuthSub for Action 界面可让 Flash 或 Silverlight 应用代表用户向受保护的 Google Data API Feed 进行身份验证。为了保持高级别的安全性,应用可通过该接口获取身份验证令牌,而无需处理用户的登录信息。
适用于 Action 的 AuthSub 是 JavaScript 版 AuthSub 的变体。与适用于 JavaScript 的 AuthSub 类似,该方法为客户端应用提供跨非 Google 网域所托管的网页进行身份验证的方法。该身份验证程序与标准 AuthSub 的不同之处在于,身份验证服务位于不同的网域(accounts.googleapis.com 而非 www.google.com),并提供了一个允许从外部网站访问该网域的 crossdomain.xml
文件。
另请参阅 Google Accounts API 群组,了解如何使用所有身份验证服务 API。
观众
本文面向的是开发访问 Google 服务的 Flash 或 Silverlight 网络应用的程序员。
本文档假定您了解 Google Data API 协议和 AuthSub 接口的一般概念。此外,本教程还假定您已知道如何使用 ActionScript 进行编程。
受支持的环境
Firefox 1.5 及更高版本和 Internet Explorer 6.0 及更高版本以及 Flash 9.0 或更高版本、Silverlight 2.0 或更高版本均支持适用于 Action 的 AuthSub。
适用于 Action 的 AuthSub 的工作原理
下面简要介绍了 Web 应用、Google 身份验证服务和 Google 数据服务之间的通信原理:
- 要代表用户访问 Google 数据服务,Web 应用必须具有有效的身份验证令牌。通常,应用将此令牌存储在 Cookie 中;如果没有这样的 Cookie,则 Web 应用必须通过 AuthSub 获取此令牌。为了获取令牌,Web 应用会对 Authentication 服务进行用于 Action 的 AuthSub 登录调用,并指定要访问的服务。
- 收到 Web 应用的请求后,Authentication 服务会将用户重定向到“访问请求”页面。此页面会提示用户登录其 Google 帐号,并要求用户授予或拒绝其 Google 服务的访问权限。
- 用户决定是授予还是拒绝 Web 应用的访问权限。如果用户拒绝授予访问权限,则会定向到 Google 页面,而不是 Web 应用。
- 如果用户成功登录并授予访问权限,Authentication 服务会将用户重定向回进行原始调用的 Web 应用网址。重定向通过查询参数传递指定服务的身份验证令牌。应用应在 Web 应用网域下,将令牌作为 Cookie 存储在用户的浏览器中。令牌在撤销之前一直有效。(如需了解有关何时撤消令牌的建议,请参阅令牌简介部分。)
- Web 应用会与 Google 数据服务联系,并将身份验证令牌以及发送到服务的每个请求一并发送。
- 如果 Google 数据服务识别出令牌,它会提供请求的数据。
使用适用于身份验证的 AuthSub 接口
适用于 Action 的 AuthSub(即 AuthSubAS)为使用 Google Data API 的 Flash(或 Silverlight)应用提供跨网域 AuthSub 端点。
AuthSubAS 提供了在 google.com 上找到的 AuthSub 端点的镜像,以及一个允许 Flash(或 Silverlight)额外访问这些端点的 crossdomain.xml
文件。例如,可通过访问 https://accounts.googleapis.com/accounts/AuthSubSessionToken 来使用端点 AuthSubSessionToken。
以下步骤详细介绍了获取身份验证令牌并使用该令牌从 Flash 应用访问 Google 服务的过程。
- 设置跨网域政策。
若要以跨网域方式使用 Flash,则必须通过要访问的每个外部网域的政策对其进行初始化。为此,请为每个网域调用 Action 方法
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
(Picasa Web,稍后将访问示例)的政策。 - 请求一次性令牌。
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');
此方法需要范围值。每项 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)"
相册服务的 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 用于执行 Action 的令牌。在大多数情况下,您无需知道此信息。
每个身份验证令牌都特定于以下数据:
- Google 服务范围
- 用户的 Google 帐号
- 客户端应用
令牌数据可确保只有指定的第三方应用才能请求数据,且请求仅限于来自指定范围和用户帐号的数据。
范围、用户和客户端的组合中,一个令牌在任何时候都有效。每当给定用户需要访问新的 Google 服务时,Web 应用都必须请求新的令牌。令牌覆盖的范围取决于 Google 服务,Google 服务可能会选择限制对特定类型的数据或活动的访问,例如只读权限。
由 AuthSub for Action 接口返回的令牌可以根据需要使用多次,直到令牌被撤消为止。令牌的生命周期由应用管理,兼顾安全性与便利性。Google 建议每次启动新会话时都请求新令牌。
某些 Google 服务可能只允许已注册并使用安全令牌的 Web 应用访问。此类服务不支持适用于 Action 的 AuthSub。要使用安全令牌,您的组织必须向 Google 注册 SSL 证书并签署针对这些数据 Feed 的所有请求。