在 IBM Bluemix 云平台上开发并部署您的下一个应用。
HTTP 是众所周知的 Internet 协议。尽管 java.net 包提供基本的通过 HTTP 协议访问资源的功能,但是它既不够灵活,功能也不是足够强大,不能满足现代 web 应用程序的需求。Apache Jakarta Commons HttpClient 使用最新的 HTTP 标准和规范,通过在客户端提供一个高效且功能丰富的包实现来填补这一空白。HttpClient 也被开源项目和商业软件产品广泛采用。
在本文中,学习如何扩展 HttpClient 认证模型。使用第三方 OAuth 库来添加 OAuth 认证。本文还讨论了 HttpClient v3.0.x 和 v4.x 之间的差异。
回页首
HttpClient 处理服务器认证几乎是透明的。只需要提供登录证书。但是,不同版本有所差异。
setCredentials(AuthScope authscope, Credentials cred)
和 getCredentials(AuthScope authscope)
方法设置或检索。建立在 HttpClient 上的自动授权可以禁用,使用 HttpMethod
类的 setDoAuthentication(boolean doAuthentication)
方法。更改只影响那个方法实例。
也支持先占式(Preemptive)基础认证功能,通过设置 setAuthenticationPreemptive(Boolean preemptive)
实现,但是只 支持先占式基础服务。
CredentialProvider
来维护用户证书集,并为一个特定认证范围提供证书。通过将 CredentialProvider
添加到 HttpContext,这表示一个 HTTP 流程的执行状态,HttpClient 能够根据主机名、端口号和范围自动进行认证。
先占式认证不再以开箱即用的方式提供,滥用先占式认证可能引起用户证书泄漏。然而,如果您想要一个先占式认证,可以使用一个标准 HttpClient 扩展(比如协议拦截器)启用。
回页首
OAuth 是一个开放的协议,以一种简单且标准的方法支持来自桌面和 web 应用程序的安全 API 授权。有了 OAuth,一个资源所有者可以授权第三方应用程序访问受保护的资源,而不损害用户证书。(OAuth 协议于 2007 年 10 月在版本 1.0 中确定,在 2009 年 6 月(修订版 A)进行改进。OAuth 2.0 规范正在开发之中。)
图 1 显示了典型的 three-legged OAuth dance。
依照上图编号,当 OAuth three-legged 握手启动时:
当保护的 OAuth 资源被请求后,通常,客户端将得到一个 HTTP 401 的响应,包含一个 WWW-Authentication 头部:
WWW-Authenticate: OAuth realm=<your_realm>
WWW-Authentication 头部指出保护资源的认证模式。然后,HttpClient 可以根据 WWW-Authenticate 头部执行 OAuth 认证。
默认情况下,在 HttpClient 中仅支持基础认证、摘要认证和 NTLM 认证。下一小节 介绍如何在 HttpClient 模式下添加和使用 OAuth 认证。
除了原生支持基础、摘要和 NTLM 认证之外,HttpClient 有一个机制来插入自定义的额外认证模式,使用 AuthScheme 接口。要使用一个定制的认证模式:
回页首
Oauth.net 提供一个开源 Java? 库。如上所述,要使用自定义的认证,您需要提供您自己的 AuthScheme 和证书类。OAuth 库已经实现了它自己的 OAuthScheme
、OAuthSchemeFactory
和 OAuthCredentials
。您可以利用它们来添加 OAuth 支持到您的 HttpClient 应用程序。
要启用 HttpClient 4.0.1 的一个 OAuth 认证模式:
OAuthCredentials
。HttpContext
对象来在请求执行之前定制 HTTP 认证内容,或者您可以在请求执行之后检查其状态。通过设置 HttpContext
对象的 http.auth.scheme-pref
属性修改认证默认首选项。清单 1 显示了一个示例。注意代码中获取您自己的 OAuthAccessor 的方法被省略了,因为它由您的具体实现而定。
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" }));
很多 web 网站支持 OAuth,比如 LinkedIn。以下示例展示如何使用有 OAuth 支持的 HttpClient 从 LinkedIn 获取一个用户的配置文件。
清单 2 是样例代码。
AccessToken
和 Secret
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 以得到批准,如下所示。
在您自己的回调 servlet 中,使用清单 3 中的代码获取验证器,然后使用它来请求 AccessToken
和 Secret
。
AccessToken
和 Secret
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));
使用上述代码,注册 OAuthScheme
。使用 accessor
对像设置证书。
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 所示。
<?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=&key=84546207 &authToken=SMl9&authType=name& trk=api*a113393*s121886*</url> </site-standard-profile-request> </person>
HttpClient 不支持开箱即用的先占式认证,但是您可以使用一个协议拦截器事先引入一个 AuthScheme 实例到执行上下文。这个拦截器必须在标准认证拦截器之前 添加到协议处理链。
仅支持 OAuth 1.0 的 web 网站不提供 “挑战” 响应。要使用 OAuth 认证,您需要使用先占式认证。OAuth 库也使用 HttpClient 4.0.1 的 HttpRequestInterceptor
使其得以实现。清单 6 中显示的样例代码可以启用先占式认证。
HttpRequestInterceptor preemptiveAuth = new PreemptiveAuthorizer(); httpClient.addRequestInterceptor(preemptiveAuth, 0);
回页首
HttpClient 原生支持基础认证、摘要认证和 NTLM 认证。在 HttpClient 3.0.x 中添加一个自定义的 AuthScheme 与在 4.0.1 中添加有所不同。
Scheme
类,来实现 AuthScheme 接口。关于编写该函数的解释不在本文讨论范围中。 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)。
AuthPolicy.AUTH_SCHEME_PRIORITY
首选项来启用自定义的 AuthScheme
,如下所示。
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);
HttpClient 3.0.x 也支持先占式认证,如下所示。
client.getParams().setAuthenticationPreemptive(true);
然而,在该模式下,您只能使用基础认证。对于一个需要 OAuth 先占式认证的网站,您不能使用 HttpClient 3.0.x。
回页首
HttpClient 认证模式提供一种机制来进行自身扩展,对于在开发期间使用 HttpClient 的应用程序来说,利用一个第三方 OAuth 库来添加 OAuth 认证是比较容易的。然而对于 HttpClient 3.0.x 有一些限制。
联系客服