跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

添加 OAuth 认证支持到 HttpClient

Zheng (Erik) Bi, 资深软件工程师, IBM
http://www.ibm.com/developerworks/i/p-zbi.jpg
Zheng Bi 从事 IBM 产品 J2EE/Web2.0 方面的工作,包括 WBSE 和 IBM Mashup Center。他有丰富的 web 应用程序开发技术经验。Zheng 目前从事 Web 2.0 安全性工作。
Xiaofeng Yu, 顾问软件工程师, IBM
http://www.ibm.com/developerworks/i/p-xfengyu.jpg
Xiaofeng Yu 于 2005 年加入 IBM。他在 web 应用程序开发方面有丰富的经验,他致力于 IBM Web 2.0 产品、Lotus Connections 和 Lotus Mashups 的研究。Xiaofeng 目前从事 Web 2.0 安全性工作。

简介: 对于现代 web 开发,使用 HTTP 协议访问资源确实有点麻烦。在本文中,学习 HttpClient 的认证模块如何帮助提供 OAuth 认证支持。学习扩展认证模块来使用一个自定义的认证模式。通过一个示例(包括样例代码)展示如何使用 oauth.net 提供的这个开源库来将 OAuth 认证支持添加到 HttpClient 组件。

发布日期: 2011 年 12 月 01 日
级别: 初级 原创语言: 英文
访问情况 : 3516 次浏览
评论: 


简介

HTTP 是众所周知的 Internet 协议。尽管 java.net 包提供基本的通过 HTTP 协议访问资源的功能,但是它既不够灵活,功能也不是足够强大,不能满足现代 web 应用程序的需求。Apache Jakarta Commons HttpClient 使用最新的 HTTP 标准和规范,通过在客户端提供一个高效且功能丰富的包实现来填补这一空白。HttpClient 也被开源项目和商业软件产品广泛采用。

在本文中,学习如何扩展 HttpClient 认证模型。使用第三方 OAuth 库来添加 OAuth 认证。本文还讨论了 HttpClient v3.0.x 和 v4.x 之间的差异。


认证机制

HttpClient 处理服务器认证几乎是透明的。只需要提供登录证书。但是,不同版本有所差异。

HttpClient v3.x
证书存储在 HttpState 实例中,可以使用 setCredentials(AuthScope authscope, Credentials cred)getCredentials(AuthScope authscope) 方法设置或检索。建立在 HttpClient 上的自动授权可以禁用,使用 HttpMethod 类的 setDoAuthentication(boolean doAuthentication) 方法。更改只影响那个方法实例。

也支持先占式(Preemptive)基础认证功能,通过设置 setAuthenticationPreemptive(Boolean preemptive) 实现,但是 支持先占式基础服务。

HttpClient v4.x
您应该实例化 CredentialProvider 来维护用户证书集,并为一个特定认证范围提供证书。通过将 CredentialProvider 添加到 HttpContext,这表示一个 HTTP 流程的执行状态,HttpClient 能够根据主机名、端口号和范围自动进行认证。

先占式认证不再以开箱即用的方式提供,滥用先占式认证可能引起用户证书泄漏。然而,如果您想要一个先占式认证,可以使用一个标准 HttpClient 扩展(比如协议拦截器)启用。


OAuth

OAuth 是一个开放的协议,以一种简单且标准的方法支持来自桌面和 web 应用程序的安全 API 授权。有了 OAuth,一个资源所有者可以授权第三方应用程序访问受保护的资源,而不损害用户证书。(OAuth 协议于 2007 年 10 月在版本 1.0 中确定,在 2009 年 6 月(修订版 A)进行改进。OAuth 2.0 规范正在开发之中。)

图 1 显示了典型的 three-legged OAuth dance。


图 1. Three-legged OAuth dance
图表概括显示下述 Browser、Consumer 和 Service Provider 的 10 个步骤。

依照上图编号,当 OAuth three-legged 握手启动时:

  1. 客户为 OAuth 握手请求一个临时令牌。这个令牌用于维护握手会话。
  2. 确认了客户之后,服务器提供商颁发一个短期请求令牌。
  3. 客户发送一个 HTTP 重定向响应用户浏览器,然后将用户引导到服务供应商进行授权。
  4. 用户检查授权请求,并在服务提供商网站上授予客户访问权限(如果他信任该客户)。
  5. 服务器供应商确定授权,然后发送一个 HTTP 重定向来响应用户浏览器。
  6. 用户浏览器被重定向到客户回调 URL,在这里客户可以完成握手的其余部分。
  7. 客户使用上一步传递的验证器从服务提供商请求访问令牌。
  8. 成功确认之后,服务提供商颁发访问令牌来访问受保护资源。
  9. OAuth 握手完成之后,访问令牌颁发,客户可以使用这个访问令牌代表用户访问受保护的数据。
  10. 服务提供商验证每个到来的 OAuth 请求,如果客户被授权,就返回受保护资源。

当保护的 OAuth 资源被请求后,通常,客户端将得到一个 HTTP 401 的响应,包含一个 WWW-Authentication 头部:

WWW-Authenticate: OAuth realm=<your_realm>

WWW-Authentication 头部指出保护资源的认证模式。然后,HttpClient 可以根据 WWW-Authenticate 头部执行 OAuth 认证。

默认情况下,在 HttpClient 中仅支持基础认证、摘要认证和 NTLM 认证。下一小节 介绍如何在 HttpClient 模式下添加和使用 OAuth 认证。

添加一个自定义的认证模式

除了原生支持基础、摘要和 NTLM 认证之外,HttpClient 有一个机制来插入自定义的额外认证模式,使用 AuthScheme 接口。要使用一个定制的认证模式: 

  1. 实现 AuthScheme 接口。
  2. 使用 AuthPolicy.registerAuthScheme() 注册自定义的 AuthScheme 。
  3. 在 AuthPolicy.AUTH_SCHEME_PRIORITY 首选项中包含这个自定义的 AuthScheme(见本文后面的 HttpClient 3.0.x OAuth 支持)。

使用 oauth.net 的 Java 库来扩展 HttpClient 4.0.1

Oauth.net 提供一个开源 Java™ 库。如上所述,要使用自定义的认证,您需要提供您自己的 AuthScheme 和证书类。OAuth 库已经实现了它自己的 OAuthSchemeOAuthSchemeFactoryOAuthCredentials。您可以利用它们来添加 OAuth 支持到您的 HttpClient 应用程序。

要启用 HttpClient 4.0.1 的一个 OAuth 认证模式:

  1. 在 HttpClient 中注册这个新的 OAuth 认证机制。
  2. 提供一个新 OAuthCredentials
  3. HttpClient 使用一个有序偏好来选择正确的认证机制。您可以使用本地 HttpContext 对象来在请求执行之前定制 HTTP 认证内容,或者您可以在请求执行之后检查其状态。通过设置 HttpContext 对象的 http.auth.scheme-pref 属性修改认证默认首选项。

清单 1 显示了一个示例。注意代码中获取您自己的 OAuthAccessor 的方法被省略了,因为它由您的具体实现而定。


清单 1. 启用 HttpClient 4.0.1 的一个 OAuth 认证模式
				
AbstractHttpClient httpClient = new DefaultHttpClient();
//register the OAuthScheme
httpClient.getAuthSchemes().register(OAuthSchemeFactory.SCHEME_NAME, 
new OAuthSchemeFactory()); 
//get the OAuthAccessor object
OAuthAccessor accessor = yourMethodToGetOAuthAccessor();
//set credentials 
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM,
OAuthSchemeFactory.SCHEME_NAME),
new OAuthCredentials(accessor));
//Adjust the authentication scheme selection
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute("http.auth.scheme-pref", Arrays.asList(new String[] {
"oauth", "digest", "basic"
}));

示例:使用 OAuth 从 LinkedIn 获取配置文件

很多 web 网站支持 OAuth,比如 LinkedIn。以下示例展示如何使用有 OAuth 支持的 HttpClient 从 LinkedIn 获取一个用户的配置文件。

  1. 您需要一个 LinkedIn 账户,需要创建一个应用程序。然后您可以获取 API Key,这在 OAuth 术语中称为 Consumer Key。图 2 显示了一个例子。

    图 2. 获取您应用程序的 Consumer Key 和 Secret
    显示应用程序创建成功消息的屏幕截图,有应用程序详细说明,包含 Company、Application 名称、API Key 和 Secret Key。

  2. 有了 Consumer Key 和 Secret Key 之后,向 LinkedIn 发出一个请求来获取 AccessToken 和 Secret,使用以下内容:
    • LinkedIn Oauth 端点 URL
    • 根路径:https://api.linkedin.com
    • 请求令牌路径:/uas/oauth/requestToken
    • 访问令牌路径:/uas/oauth/accessToken
    • 授权路径:/uas/oauth/authorize

    清单 2 是样例代码。



    清单 2. 从 LinkedIn 获取 AccessTokenSecret
    						
    String baseURL = "https://api.linkedin.com";
    String requestTokenURL = baseURL + "/requestToken";
    String authorizationURL = baseURL + "/authorize";
    String accessTokenURL = baseURL + "/accessToken";
    
    String consumerKey="hP80ApmoJkO-9ZHuXC97olUzD1egVI75zKoff9SCKFFTY9zjc
       vWRRRbiNrWbcKIX";
    String consumerSecret="toAk3oV1wKuon9W51lfELLHtZSxBZHih-qMyeDIBrIB2Y1hCASbpmK313
       Wubmrd2";
    OAuthServiceProvider provider = new OAuthServiceProvider(
    				requestTokenURL, authorizationURL, accessTokenURL);
    OAuthConsumer consumer = new OAuthConsumer(
    		"DemoOAuth", consumerKey, consumerSecret, provider);
    OAuthAccessor accessor = new OAuthAccessor(consumer);
    OAuthClient client = new OAuthClient(new HttpClient4());
    List<Parameter> parameters = new ArrayList<OAuth.Parameter>();
    parameters.add(new Parameter("oauth_callback", "yourAppcallbackurl"));
    OAuthMessage msg = client.getRequestTokenResponse(accessor,
    					"POST", parameters);
    String requestToken = msg.getParameter(OAuth.OAUTH_TOKEN);
    String requestSecret = msg.getParameter(OAuth.OAUTH_TOKEN_SECRET);
    

    现在您有了 URL:

    authorizationURL + "?" + OAuth.OAUTH_TOKEN+ "=" + requestToken
    

    如果在一个 web 应用程序中,用户应该访问 LinkedIn 或被重定向到 LinkedIn 以得到批准,如下所示。



    图 3. 用户批准
    显示授权 OAuth 访问您的 LinkedIn 账户的过程的屏幕截图

    在您自己的回调 servlet 中,使用清单 3 中的代码获取验证器,然后使用它来请求 AccessTokenSecret



    清单 3. 请求 AccessTokenSecret
    						
    
    OAuthMessage msg = OAuthServlet.getMessage(request, null);
    String requestToken = msg.getParameter(OAuth.OAUTH_TOKEN);
    String verifier = msg.getParameter(OAuth.OAUTH_VERIFIER);
    …
    get the accessor object in List 1…
    ….
    OAuthClient oauthClient = new OAuthClient(new HttpClient4());
    List<Parameter> list = new ArrayList<Parameter>();
    list.add(new Parameter(OAuth.OAUTH_VERIFIER, verifier));
    OAuthMessage returned = oauthClient.getAccessToken(accessor,
           "POST", list);
    String accessToken = returned.getParameter(OAuth.OAUTH_TOKEN));
    String accessKey = returned.getParameter(OAuth.OAUTH_TOKEN_SECRET));
                

  3. 添加 OAuth 支持到 HttpClient。

    使用上述代码,注册 OAuthScheme。使用 accessor 对像设置证书。

  4. 使用 OAuth 认证发送请求到 LinkedIn。

    清单 4. 使用 OAuth 认证发送请求到 LinkedIn
    						
    HttpGet httpget = new HttpGet("https://api.linkedin.com/v1/people/~");
    //Run the http get method under the modified context
    httpClient.execute(httpget, localContext);
    

    现在您可以使用 OAuth 认证通过 HttpClient 获取用户配置文件,如清单 5 所示。

    清单 5. LinkedIn 返回用户信息

    							
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <person>
      <first-name>Zheng</first-name>
      <last-name>BI</last-name>
      <headline>SE at IBM</headline>
      <site-standard-profile-request>
    <url>http://www.linkedin.com/profile?viewProfile=&amp;key=84546207
    &amp;authToken=SMl9&amp;authType=name&amp;
    trk=api*a113393*s121886*</url>
      </site-standard-profile-request>
    </person>
                

先占式模式支持

HttpClient 不支持开箱即用的先占式认证,但是您可以使用一个协议拦截器事先引入一个 AuthScheme 实例到执行上下文。这个拦截器必须在标准认证拦截器之前 添加到协议处理链。

仅支持 OAuth 1.0 的 web 网站不提供 “挑战” 响应。要使用 OAuth 认证,您需要使用先占式认证。OAuth 库也使用 HttpClient 4.0.1 的 HttpRequestInterceptor 使其得以实现。清单 6 中显示的样例代码可以启用先占式认证。


清单 6. 启用先占式认证
				
HttpRequestInterceptor preemptiveAuth = new PreemptiveAuthorizer();
httpClient.addRequestInterceptor(preemptiveAuth, 0);
            


HttpClient 3.0.x OAuth 支持

HttpClient 原生支持基础认证、摘要认证和 NTLM 认证。在 HttpClient 3.0.x 中添加一个自定义的 AuthScheme 与在 4.0.1 中添加有所不同。

  1. OAuth Java Lib 不提供 HttpClient 3.0.x 支持,因此您需要创建您自己的 Scheme 类,来实现 AuthScheme 接口。关于编写该函数的解释不在本文讨论范围中。
  2. 使用 AuthPolicy.registerAuthScheme() 注册 OAuthScheme(见 http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/auth/AuthPolicy.html#registerAuthScheme%28java.lang.String,%20java.lang.Class%29)
  3. 更改 AuthPolicy.AUTH_SCHEME_PRIORITY 首选项来启用自定义的 AuthScheme,如下所示。

    清单 7. 启用自定义的 AuthScheme
    						
    HttpClient client = new HttpClient();
    List authPrefs = new ArrayList(2);
    authPrefs.add(AuthPolicy.OAUTH);
    authPrefs.add(AuthPolicy.DIGEST);
    authPrefs.add(AuthPolicy.BASIC);
    client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
                

v3.0.x 的局限性

HttpClient 3.0.x 也支持先占式认证,如下所示。


清单 8. HttpClient 3.0.x 支持先占式认证
				
client.getParams().setAuthenticationPreemptive(true);
            

然而,在该模式下,您只能使用基础认证。对于一个需要 OAuth 先占式认证的网站,您不能使用 HttpClient 3.0.x。


结束语

HttpClient 认证模式提供一种机制来进行自身扩展,对于在开发期间使用 HttpClient 的应用程序来说,利用一个第三方 OAuth 库来添加 OAuth 认证是比较容易的。然而对于 HttpClient 3.0.x 有一些限制。


参考资料

学习

  • 阅读 OAuth 1.0 Protocol,这是 Internet Engineering Task Force (IETF) 的一个产品,代表 IETF 社区的共识。

  • 从 Apache 阅读更多关于 HttpCore 和 HttpClient 4.1 的信息。

  • 阅读 认证机制,使用 HTTP 服务器或者端口进行认证。

  • 访问 OAuth.net 获取 OAuth 1.0 和 2.0 各个方面的信息,包括与 OAuth 协议实现相关的代码,比如本文中所用的 Java OAuth 库。

  • 研究 LinkedIn DeveloperNetwork,寻找 LinkedIn 开源 API。

  • developerWorks Web development 专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。

  • developerWorks Ajax 资源中心:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。

  • developerWorks Web 2.0 资源中心,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 Web 2.0 新手入门 栏目,迅速了解 Web 2.0 的相关概念。

  • 查看 HTML5 专题,了解更多和 HTML5 相关的知识和动向。

获得产品和技术

讨论

作者简介

http://www.ibm.com/developerworks/i/p-zbi.jpg

Zheng Bi 从事 IBM 产品 J2EE/Web2.0 方面的工作,包括 WBSE 和 IBM Mashup Center。他有丰富的 web 应用程序开发技术经验。Zheng 目前从事 Web 2.0 安全性工作。

http://www.ibm.com/developerworks/i/p-xfengyu.jpg

Xiaofeng Yu 于 2005 年加入 IBM。他在 web 应用程序开发方面有丰富的经验,他致力于 IBM Web 2.0 产品、Lotus Connections 和 Lotus Mashups 的研究。Xiaofeng 目前从事 Web 2.0 安全性工作。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=777686
ArticleTitle=添加 OAuth 认证支持到 HttpClient
publish-date=12012011

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。