OAuth 协议致力于使网站和应用程序(统称为消费方 Consumer)能够在无须用户透露其认证信息的情况下,通过 API 访问该用户在服务提供方(Service Provider)那里的受保护资源。更一般地说,OAuth 为 API 认证提供了一个可自由实现且通用的方法。目前互联网很多服务如 Open API 等都提供了 OAuth 认证服务,OAuth 标准也逐渐成为开放资源授权的标准。本文讨论如何使用 Google Code 上提供的 OAuth Java 库来实现基于 OAuth 认证的 Java 应用,并结合 Google 的 Data Service,给出使用 OAuth 方式访问 Google Data 的例子。
OAuth 是由 Blaine Cook、Chris Messina、Larry Halff 及 David Recordon 共同发起的,目的在于为 API 访问授权提供一个安全、开放的标准。
基于 OAuth 认证授权具有以下特点:
OAuth 的解决方案如下图所示。
图 1. OAuth Solution
如图 1 所示 OAuth 解决方案中用户、消费方及其服务提供方之间的三角关系:当用户需要 Consumer 为其提供某种服务时,该服务涉及到需要从服务提供方那里获取该用户的保护资源。OAuth 保证:只有在用户显式授权的情况下(步骤 4),消费方才可以获取该用户的资源,并用来服务于该用户。
从宏观层次来看,OAuth 按以下方式工作:
在了解 OAuth 认证流程之前,我们先来了解一下 OAuth 协议的一些基本术语定义:
图 2. OAuth 授权流程(摘自 OAuth 规范)
对于图 2 具体每一执行步骤,解释如下:
总的来讲,在 OAuth 的技术体系里,服务提供方需要提供如下基本的功能:
而对于消费方而言,需要如下的基本功能:
我们具体来看一个使用 OAuth 认证的例子。
在传统的网站应用中,如果您想在网站 A 导入网站 B 的联系人列表,需要在网站 A 输入您网站 B 的用户名、密码信息。例如,您登陆 Plaxo (https://www.plaxo.com ),一个联系人管理网站,当您想把 GMail 的联系人列表导入到 Plaxo,您需要输入您的 GMail 用户名 / 密码,如图 3 所示:
在这里,Plaxo 承诺不会保存您在 Gmail 的密码。
如果使用 OAuth 认证,情况是不同的,您不需要向网站 A(扮演 Consumer 角色)暴露您网站 B(扮演 Service Provider 角色)的用户名、密码信息。例如,您登录 http://lab.madgex.com/oauth-net/googlecontacts/default.aspx 网站, 如图 4 所示:
点击“Get my Google Contacts”,浏览器将会重定向到 Google,引导您登录 Google,如图 5 所示:
登录成功后,将会看到图 6 的信息:
在您登录 Google,点击“Grant access”,授权 lab.madgex.com 后,lab.madgex.com 就能获得您在 Google 的联系人列表。
在上面的的例子中,网站 lab.madgex.com 扮演着 Consumer 的角色,而 Google 是 Service Provider,lab.madgex.com 使用基于 OAuth 的认证方式从 Google 获得联系人列表。
下一节,本文会给出一个消费方实现的例子,通过 OAuth 机制请求 Google Service Provider 的 OAuth Access Token,并使用该 Access Token 访问用户的在 Google 上的日历信息 (Calendar)。
作为消费方,首先需要访问 https://www.google.com/accounts/ManageDomains,从 Google 那里获得标志我们身份的 Customer Key 及其 Customer Secret。另外,您可以生成自己的自签名 X509 数字证书,并且把证书上传给 Google,Google 将会使用证书的公钥来验证任何来自您的请求。
具体的操作步骤,请读者参考 Google 的说明文档:http://code.google.com/apis/gdata/articles/oauth.html。
在您完成这些工作,您将会得到 OAuth Consumer Key 及其 OAuth Consumer Secret,用于我们下面的开发工作。
以下的代码是基于 Google Code 上提供的 OAuth Java 库进行开发的,读者可以从 http://oauth.googlecode.com/svn/code/java/core/ 下载获得。
OAuthServiceProvider serviceProvider = new OAuthServiceProvider( "https://www.google.com/accounts/OAuthGetRequestToken", "https://www.google.com/accounts/OAuthAuthorizeToken", "https://www.google.com/accounts/OAuthGetAccessToken");
OAuthConsumer oauthConsumer = new OAuthConsumer(null , "www.example.com" , "hIsGkM T4 90fKNesTtJq8Gs" , serviceProvider);
oauthConsumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1); oauthConsumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKey);
accessor = new OAuthAccessor(consumer);
Collection