2007 年 8 月
简介:为什么 AuthSub 很重要?
Google Data API(简称“GData”)的强大之处在于,它允许开发者构建与 Google 服务交互的应用。更具体地说,它们允许您访问私人用户数据以在应用中使用。借助这些 API,您可以编写应用来同步、导入、导出和以其他方式管理这些数据。虽然这些 API 赋予了您强大的能力,但您必须记住要负责任地使用它们。由于用户数据属于私密信息,因此您自然希望以安全的方式访问这些数据。其中一个关键部分是能够以安全的方式向 Google 的服务器进行身份验证。
假设您有一个很棒的新 Web 应用,希望将其与存储在 Google Web 服务中的数据相关联。现在,您需要进行身份验证才能访问此私密数据。为什么不直接使用 ClientLogin 等简单的方法?这样确实可以解决问题,但您需要处理的私密数据会更多:用户的登录凭据。ClientLogin 要求您的应用请求用户的 Google 用户名和密码。对于在用户个人机器上运行的桌面应用,这没问题,但对于基于 Web 的应用,这不太理想。除了在您自己的服务器上处理这些凭据的责任之外,或许您的一些更谨慎的用户会担心您可能会存储他们的信息。用户提出的另一个常见问题是,他们可能只希望向某个程序授予对特定服务(例如 Google 日历中的活动)的访问权限,而不希望授予对其他服务(例如 Google 文档)的访问权限。AuthSub 通过让用户通过 Google 的服务器进行身份验证来解决这两个问题,并允许您的程序仅请求所需的访问权限。
现在,您已经充分了解了 AuthSub 背后的理论,接下来该开始编码了!在本文中,我选择保持简单,在单个 ASP 页面中完成所有操作,但您应该能够轻松地将此处演示的技术集成到自己的应用中。
处理身份验证
那么,要在 Web 应用中实际使用 AuthSub,需要做些什么呢?首先,从 GData 客户端库导入一些标准内容:
<%@ Import Namespace="Google.GData.Client" %> <%@ Import Namespace="Google.GData.Extensions" %> <%@ Import Namespace="System.Net" %>
现在,您首先要做的是将用户引导至精心设计的网址。这样一来,Google 的服务器就可以处理身份验证,然后将用户重定向回您的网站。幸运的是,您无需手动生成此网址,因为有一些方法可以为您完成此操作。我们来看一个示例:
authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
- target:这是一个包含 Web 应用网址的字符串。这是用户在通过身份验证后将被重定向到的位置。
- 范围:此字符串取决于您使用的 API。它对应于 GData API 中的某个 Feed。例如,包含用户所有日历信息的 Feed 为“http://www.google.com/calendar/feeds/default/private/full”。
- 安全:这是一个布尔值,用于告知服务器您已向 Google 注册,并将以加密方式对发送给服务器的请求进行签名。此实参通常默认为 false,尤其是在测试环境中工作时。
- session:这是另一个布尔值,用于指示您需要的是“会话令牌”而不是“一次性令牌”。稍后,您将更清楚地了解此实参的作用。
用户点击生成的网址后,系统会将其转到 Google 账号页面,以便其登录自己的 Google 账号。然后,他们会被重定向回您在“target”变量中指定的网页,但会附加一个包含一次性令牌的查询参数“token”。通常情况下,此令牌只能使用一次。也就是说,它可用于对指定 Feed 执行一项操作。不过,如果您将“session”参数指定为 true,则可以将其换成“会话令牌”,该令牌可以重复使用,直到用户结束会话。您可以按以下方式执行此操作:
String token = Request.QueryString["token"]; Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
在此处,您需要从查询参数中提取令牌,并将其换成“会话令牌”。然后,为了保存该令牌以供日后使用,您可以选择将其存储在 .NET 的自动 Session
数组中。当然,您也可以选择将令牌存储在数据库中。下一步是使用此令牌发出经过身份验证的请求:
GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application"); authFactory.Token = (String) Session["token"]; CalendarService service = new CalendarService(authFactory.ApplicationName); service.RequestFactory = authFactory;
在此处,您设置了一个 CalendarService 对象,以使用 AuthSub 进行身份验证,从而与 Google Calendar API 进行交互。请注意,构造函数中用于 GAuthSubRequestFactory
的“cl”是日历的服务名称。如需了解其他服务名称,请参阅 Google Data API 常见问题解答。
安全(已注册)AuthSub
如果您选择注册 Web 应用,则可以在使用 AuthSub 时启用额外的安全级别。这样一来,您就可以对代码发出的所有请求进行数字签名,从而确保他人无法使用向您发放的 AuthSub 令牌,除非他们拥有您的私钥。第一步是确保在调用 AuthSubUtil.getRequestUrl
时通过将“secure”实参设置为 true 来生成正确的 AuthSub 链接。您还需要进行另外两项代码更改:
String token = Request.QueryString["token"]; Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString(); ... authFactory.PrivateKey = rsaKey;
首先,请注意,您现在将变量“rsaKey”传递给 exchangeForSessionToken
方法,而不是 null
。在设置与服务的连接时,我们还会使用同一变量来设置 GAuthSubRequestFactory
的属性。“rsaKey”变量是一个 RSACryptoServiceProvider
,对应于您向 Google 注册的 x509 证书的私钥组件。
生成 RSA 私钥和自签名证书可能有点令人困惑,尤其是因为 .NET 框架无法识别以 PEM 格式存储的密钥或证书。以下命令展示了如何使用 OpenSSL 工具套件生成私钥和公共证书:
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \ '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \ test_key.pem -out test_cert.pem openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \ -out test_cert.pfx -name "Testing Certificate"
第一步会生成一个私钥和一个公钥 X509 证书,两者均采用 PEM 格式,分别称为“test_key.pem”和“test_cert.pem”。请注意,该证书已设置为注册到位于美国加利福尼亚州山景城的“www.example.com”。请在此处替换为贵公司的相应值。“test_cert.pem”文件包含您需要在 AuthSub 注册页面上提交的信息。
第二步会根据您的私钥和证书生成 PFX 文件。此文件可以导入到 .NET 客户端库中,用于对向 GData API 发出的请求进行数字签名。以下代码展示了如何将 PFX 文件中的私钥导入到 Web 应用中:
protected AsymmetricAlgorithm getRsaKey() { X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx",""); RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider; return privateKey; }
此代码段定义的 getRsaKey()
函数可用于代替上面显示的“rsaKey”变量,以对 API 进行身份验证。当然,文件路径应替换为您生成的 PFX 文件的相应位置。
完整代码清单
要展示如何使用上一部分中演示的方法,最简单的方式是使用实际示例。以下示例代码是一个简单的 ASP 网页,它使用 AuthSub 对用户进行身份验证,然后输出用户的 Google 日历活动。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%@ Import Namespace="Google.GData.Client" %> <%@ Import Namespace="Google.GData.Extensions" %> <%@ Import Namespace="Google.GData.Calendar" %> <%@ Import Namespace="System.Net" %> <script runat="server"> void PrintCalendar() { GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp"); authFactory.Token = (String) Session["token"]; CalendarService service = new CalendarService(authFactory.ApplicationName); service.RequestFactory = authFactory; EventQuery query = new EventQuery(); query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full"); try { EventFeed calFeed = service.Query(query); foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries) { Response.Write("Event: " + entry.Title.Text + "<br/>"); } } catch (GDataRequestException gdre) { HttpWebResponse response = (HttpWebResponse)gdre.Response; //bad auth token, clear session and refresh the page if (response.StatusCode == HttpStatusCode.Unauthorized) { Session.Clear(); Response.Redirect(Request.Url.AbsolutePath, true); } else { Response.Write("Error processing request: " + gdre.ToString()); } } } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Test Site</title> </head> <body> <form id="form1" runat="server"> <h1>AuthSub Sample Page</h1> <div> <% GotoAuthSubLink.Visible = false; if (Session["token"] != null) { PrintCalendar(); } else if (Request.QueryString["token"] != null) { String token = Request.QueryString["token"]; Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString(); Response.Redirect(Request.Url.AbsolutePath, true); } else //no auth data, print link { GotoAuthSubLink.Text = "Login to your Google Account"; GotoAuthSubLink.Visible = true; GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(), "http://www.google.com/calendar/feeds/",false,true); } %> <asp:HyperLink ID="GotoAuthSubLink" runat="server"/> </div> </form> </body> </html>
总结
AuthSub 可让您的 Web 应用以安全且受控的方式访问存储在用户 Google 账号中的数据。使用 .NET 客户端库可以轻松将基于 ASP 的网站与 Google 服务集成。本文旨在帮助您入门,但我们建议您参考以下其他资源: