如何使用HttpClient认证机制
本文介绍HttpClient的认证机制,并给出示例代码。
author: ZJ 07-11-21
本文出自 “子 孑” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/51919
英文版(无代码示例): http://hc.apache.org/httpclient-3.x/authentication.html
HttpClient三种不同的认证方案: Basic, Digest and NTLM. 这些方案可用于服务器或代理对客户端的认证,简称服务器认证或代理认证。
1.服务器认证(Server Authentication)
HttpClient处理服务器认证几乎是透明的,仅需要开发人员提供登录信息(login credentials)。登录信息保存在HttpState类的实例中,可以通过 setCredentials(String realm, Credentials cred)和getCredentials(String realm)来获取或设置。
HttpClient内建的自动认证,可以通过HttpMethod类的setDoAuthentication(boolean doAuthentication)方法关闭,而且这次关闭只影响HttpMethod当前的实例。
1.1抢先认证(Preemptive Authentication)
在这种模式时,HttpClient会主动将basic认证应答信息传给服务器,即使在某种情况下服务器可能返回认证失败的应答,这样做主要是为了减少连接的建立。使用该机制如下所示:
client.getParams().setAuthenticationPreemptive(true);
|
抢先认证模式也提供对于特定目标或代理的缺省认证。如果没有提供缺省的认证信息,则该模式会失效。
Credentials defaultcreds = new UsernamePasswordCredentials("username", "password");
client.getState().setCredentials(new AuthScope("myhost", 80, AuthScope.ANY_REALM), defaultcreds);
|
Httpclient实现的抢先认证遵循rfc2617.
A client SHOULD assume that all paths at or deeper than the depth of the last symbolic element in the path field of the Request-URI also are within the protection space specified by the Basic realm value of the current challenge. A client MAY preemptively send the corresponding Authorization header with requests for resources in that space without receipt of another challenge from the server. Similarly, when a client sends a request to a proxy, it may reuse a userid and password in the Proxy-Authorization header field without receiving another challenge from the proxy server.
|
1.2服务器认证的安全方面考虑
当需要与不被信任的站点或web应用通信时,应该谨慎使用缺省的认证机制。当启动(activate)抢先认证模式,或者认证中没有明确给出认证域,主机的HttpClient将使用缺省的认证机制去试图获得目标站点的授权。
如果你提供的认证信息是敏感的,你应该指定认证域。不推荐将认证域指定为AuthScope.ANY。(只有在debugging情况下,才使用)
// To be avoided unless in debug mode
Credentials defaultcreds = new UsernamePasswordCredentials("username", "password");
client.getState().setCredentials(AuthScope.ANY, defaultcreds);
|
2.代理认证(proxy authentication)
除了登录信息需单独存放以外,代理认证与服务器认证几乎一致。用 setProxyCredentials(String realm, Credentials cred)和getProxyCredentials(String realm)设、取登录信息。
3.认证方案(authentication schemes)
3.1Basic
是HTTP中规定最早的也是最兼容的方案,遗憾的是也是最不安全的一个方案,因为它以明码传送用户名和密码。它要求一个UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。
3.2 Digest
是在HTTP1.1 中增加的一个方案,虽然不如Basic得到的软件支持多,但还是有广泛的使用。Digest方案比Basic方案安全得多,因它根本就不通过网络传送实际的密码,传送的是利用这个密码对从服务器传来的一个随机数(nonce)的加密串。
它要求一个UsernamePasswordCredentials实例,可以指定服务器端的访问空间或采用默认的登录信息。
3.3 NTLM
这是HttpClient支持的最复杂的认证协议。它Microsoft设计的一个私有协议,没有公开的规范说明。一开始由于设计的缺陷,NTLM的安全性比 Digest差,后来经过一个ServicePack补丁后,安全性则比较Digest高。
NTLM需要一个NTCredentials实例。 注意,由于NTLM不使用访问空间(realms)的概念,HttpClient利用服务器的域名作访问空间的名字。还需要注意,提供给 NTCredentials的用户名,不要用域名的前缀 - 如: "adrian" 是正确的,而 "DOMAIN\adrian" 则是错的。
NTLM认证的工作机制与basic和digest有很大的差别。这些差别一般由HttpClient处理,但理解这些差别有助避免在使用NTLM认证时出现错误。
[1] 从HttpClientAPI的角度来看,NTLM与其它认证方式一样的工作,差别是需要提供'NTCredentials'实例而不是'UsernamePasswordCredentials'(其实,前者只是扩展了后者)
[2] 对NTLM认证,访问空间是连接到的机器的域名,这对多域名主机会有一些麻烦。只有HttpClient连接中指定的域名才是认证用的域名。建议将realm设为null以使用默认的设置。
[3] NTLM只是认证了一个连接而不是一请求,所以每当一个新的连接建立就要进行一次认证,且在认证的过程中保持连接是非常重要的。 因此,NTLM不能同时用于代理认证和服务器认证,也不能用于HTTP1.0连接或服务器不支持持久连接(keep-alives)的情况。
关于NTLM认证机制更详细的研究,可参考http://davenport.sourceforge.net/ntlm.html 。
3.4选择认证
一些服务器支持多种认证方案。假设一次只能使用一种认证方案,HttpClient必须选择使用哪种。HttpClient选择是基于NTLM, Digest, Basic顺序的。
在具体情况下,可以更改该顺序。可通过参数'http.auth.scheme-priority'来实现,该参数值应该被存放在一个String类型的List中。选择优先级是按插入顺序确定的。
HttpClient client = new HttpClient();
List authPrefs = new ArrayList(2);
authPrefs.add(AuthPolicy.DIGEST);
authPrefs.add(AuthPolicy.BASIC);
// This will exclude the NTLM authentication scheme
client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
|
3.5定制认证方案
HttpClient本身支持basic, digest, and NTLM这三种认证方案。同时,它也提供了加载额外定制的认证方案的功能(通过AuthScheme接口实现)。需要使用定制的认证方案,必须实现下面的步骤:
[1]实现AuthScheme接口。
[2]通过AuthPolicy.registerAuthScheme() 注册定制的AuthScheme。
[3]将定制的AuthScheme加入到AuthPolicy.AUTH_SCHEME_PRIORITY中。
4.示例
4.1Basic authentication
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; /** * A simple example that uses HttpClient to perform a GET using Basic * Authentication. Can be run standalone without parameters. * * You need to have JSSE on your classpath for JDK prior to 1.4 * * @author Michael Becke */ public class BasicAuthenticationExample { /** * Constructor for BasicAuthenticatonExample. */ public BasicAuthenticationExample() { super(); } public static void main(String[] args) throws Exception { HttpClient client = new HttpClient(); // pass our credentials to HttpClient, they will only be used for // authenticating to servers with realm "realm" on the host // "www.verisign.com", to authenticate against // an arbitrary realm or host change the appropriate argument to null. client.getState().setCredentials( new AuthScope("www.verisign.com", 443, "realm"), new UsernamePasswordCredentials("username", "password")); // create a GET method that reads a file over HTTPS, we're assuming // that this file requires basic authentication using the realm above. GetMethod get = new GetMethod( "https://www.verisign.com/products/index.html"); // Tell the GET method to automatically handle authentication. The // method will use any appropriate credentials to handle basic // authentication requests. Setting this value to false will cause // any request for authentication to return with a status of 401. // It will then be up to the client to handle the authentication. get.setDoAuthentication(true); try { // execute the GET int status = client.executeMethod(get); // print the status and response System.out.println(status + "\n" + get.getResponseBodyAsString()); } finally { // release any connection resources used by the method get.releaseConnection(); } } }
4.2 Alternate authentication
import java.util.ArrayList; import java.util.List; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthPolicy; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; /** * <p> * A simple example that uses alternate authentication scheme selection if * several authentication challenges are returned. * </p> * * <p> * Per default HttpClient picks the authentication challenge in the following * order of preference: NTLM, Digest, Basic. In certain cases it may be * desirable to force the use of a weaker authentication scheme. * </p> * * @author Oleg Kalnichevski */ public class AlternateAuthenticationExample { /** * Constructor for BasicAuthenticatonExample. */ public AlternateAuthenticationExample() { super(); } public static void main(String[] args) throws Exception { HttpClient client = new HttpClient(); client.getState().setCredentials( new AuthScope("myhost", 80, "myrealm"), new UsernamePasswordCredentials("username", "password")); // Suppose the site supports several authetication schemes: NTLM and // Basic // Basic authetication is considered inherently insecure. Hence, NTLM // authentication // is used per default // This is to make HttpClient pick the Basic authentication scheme over // NTLM & Digest List<String> authPrefs = new ArrayList<String>(3); authPrefs.add(AuthPolicy.BASIC); authPrefs.add(AuthPolicy.NTLM); authPrefs.add(AuthPolicy.DIGEST); client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); GetMethod httpget = new GetMethod( "http://myhost/protected/auth-required.html"); try { int status = client.executeMethod(httpget); // print the status and response System.out.println(status); System.out.println(httpget.getStatusLine()); System.out.println(httpget.getResponseBodyAsString()); } finally { // release any connection resources used by the method httpget.releaseConnection(); } } }
4.3 Custom authentication
import java.util.ArrayList; import java.util.Collection; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.auth.AuthPolicy; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.AuthenticationException; import org.apache.commons.httpclient.auth.MalformedChallengeException; import org.apache.commons.httpclient.params.DefaultHttpParams; import org.apache.commons.httpclient.params.HttpParams; /** * A simple custom AuthScheme example. The included auth scheme is meant for * demonstration purposes only. It does not actually implement a usable * authentication method. */ public class CustomAuthenticationExample { @SuppressWarnings("unchecked") public static void main(String[] args) { // register the auth scheme AuthPolicy.registerAuthScheme(SecretAuthScheme.NAME, SecretAuthScheme.class); // include the scheme in the AuthPolicy.AUTH_SCHEME_PRIORITY preference, // this can be done on a per-client or per-method basis but we'll do it // globally for this example HttpParams params = DefaultHttpParams.getDefaultParams(); ArrayList<String> schemes = new ArrayList<String>(); schemes.add(SecretAuthScheme.NAME); schemes.addAll((Collection) params .getParameter(AuthPolicy.AUTH_SCHEME_PRIORITY)); params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes); // now that our scheme has been registered we can execute methods // against // servers that require "Secret" authentication... } /** * A custom auth scheme that just uses "Open Sesame" as the authentication * string. */ private class SecretAuthScheme implements AuthScheme { public static final String NAME = "Secret"; public SecretAuthScheme() { // All auth schemes must have a no arg constructor. } public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException { return "Open Sesame"; } public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException { return "Open Sesame"; } public String getID() { return NAME; } public String getParameter(String name) { // this scheme does not use parameters, see RFC2617Scheme for an // example return null; } public String getRealm() { // this scheme does not use realms return null; } public String getSchemeName() { return NAME; } public boolean isConnectionBased() { return false; } public void processChallenge(String challenge) throws MalformedChallengeException { // Nothing to do here, this is not a challenge based // auth scheme. See NTLMScheme for a good example. } public boolean isComplete() { // again we're not a challenge based scheme so this is always true return true; } } }
4.4 Interactive authentication
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScheme; import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.CredentialsProvider; import org.apache.commons.httpclient.auth.NTLMScheme; import org.apache.commons.httpclient.auth.RFC2617Scheme; import org.apache.commons.httpclient.methods.GetMethod; /** * A simple example that uses HttpClient to perform interactive authentication. * * @author Oleg Kalnichevski */ public class InteractiveAuthenticationExample { /** * Constructor for InteractiveAuthenticationExample. */ public InteractiveAuthenticationExample() { super(); } public static void main(String[] args) throws Exception { InteractiveAuthenticationExample demo = new InteractiveAuthenticationExample(); demo.doDemo(); } private void doDemo() throws IOException { HttpClient client = new HttpClient(); client.getParams().setParameter(CredentialsProvider.PROVIDER, new ConsoleAuthPrompter()); GetMethod httpget = new GetMethod( "http://target-host/requires-auth.html"); httpget.setDoAuthentication(true); try { // execute the GET int status = client.executeMethod(httpget); // print the status and response System.out.println(status); System.out.println(httpget.getStatusLine().toString()); System.out.println(httpget.getResponseBodyAsString()); } finally { // release any connection resources used by the method httpget.releaseConnection(); } } public class ConsoleAuthPrompter implements CredentialsProvider { private BufferedReader in = null; public ConsoleAuthPrompter() { super(); this.in = new BufferedReader(new InputStreamReader(System.in)); } private String readConsole() throws IOException { return this.in.readLine(); } public Credentials getCredentials(final AuthScheme authscheme, final String host, int port, boolean proxy) throws CredentialsNotAvailableException { if (authscheme == null) { return null; } try { if (authscheme instanceof NTLMScheme) { System.out.println(host + ":" + port + " requires Windows authentication"); System.out.print("Enter domain: "); String domain = readConsole(); System.out.print("Enter username: "); String user = readConsole(); System.out.print("Enter password: "); String password = readConsole(); return new NTCredentials(user, password, host, domain); } else if (authscheme instanceof RFC2617Scheme) { System.out.println(host + ":" + port + " requires authentication with the realm '" + authscheme.getRealm() + "'"); System.out.print("Enter username: "); String user = readConsole(); System.out.print("Enter password: "); String password = readConsole(); return new UsernamePasswordCredentials(user, password); } else { throw new CredentialsNotAvailableException( "Unsupported authentication scheme: " + authscheme.getSchemeName()); } } catch (IOException e) { throw new CredentialsNotAvailableException(e.getMessage(), e); } } } }
相关推荐
2. **认证和安全**:HttpClient支持多种认证机制,包括基本认证、摘要认证等。同时,它也支持HTTPS,提供了SSL/TLS的安全传输。 3. **重定向处理**:HttpClient可以自动处理HTTP状态码3xx的重定向,也可以手动控制...
6. **认证和安全**:HttpClient支持多种认证机制,包括基本认证、摘要认证、NTLM等。同时,它也可以处理HTTPS连接,配置SSL上下文以实现安全通信。 7. **异步编程**:HttpClient 4.5及以上版本引入了...
3. **身份验证**:HttpClient支持多种身份验证机制,包括基本认证、摘要认证、NTLM、Kerberos等,能够处理跨域和多层代理的认证问题。 4. **Cookie管理**:HttpClient内置了Cookie管理器,可以处理服务器返回的...
4. 执行请求:使用HttpClient的execute方法发送请求,返回HttpResponse对象。 5. 处理响应:获取HttpResponse的状态码、头部信息,并通过HttpEntity获取实体内容。 四、HttpClient的高级特性 1. 连接管理:...
4. **认证和安全机制**:HttpClient 支持多种认证机制,如 Basic、Digest、NTLM 和 Kerberos。源码中包含了这些认证的实现,可以帮助我们理解如何处理网络身份验证。同时,它也支持 SSL/TLS 加密,确保数据传输的...
5. **身份验证**:HttpClient支持多种认证机制,如Basic、Digest、NTLM等,能够处理Web服务器或代理服务器的身份验证需求。 6. **自定义化**:HttpClient的设计允许用户根据需要高度定制行为,比如实现自己的Cookie...
5. **认证和授权**:HttpClient支持多种认证机制,如Basic、Digest、NTLM和Kerberos,可以处理HTTP基本认证、摘要认证以及Windows域认证。 6. **重定向处理**:HttpClient自动处理HTTP状态码3xx的重定向,但允许...
6. **认证**:HttpClient 支持多种认证机制,包括基本认证、摘要认证、NTLM等。通过`CredentialsProvider`和`Authenticator`接口,可以方便地配置和处理认证过程。 7. **HTTP/1.1与HTTP/2**:HttpClient 4.5.x开始...
5. **认证和安全**:HttpClient 4.2.1支持多种身份验证机制,包括Basic、Digest和NTLM。同时,它也支持HTTPS,通过`SSLContext`和`KeyStore`进行证书管理和加密。 6. **Cookie管理**:HttpClient 4.2.1的`...
2. **连接管理**:HttpClient提供了一种灵活的连接管理机制,可以控制连接池的大小,避免过多的TCP连接创建和销毁,从而提高性能。 3. **线程安全**:HttpClient设计为线程安全,可以在多线程环境中使用,而无需...
7. **身份验证**:支持多种认证机制,如 Basic、Digest、NTLM 和 Kerberos,可以处理跨域和多层认证。 8. **SSL 支持**:HttpClient 4.3 对 HTTPS 协议有良好的支持,可以配置 SSL 上下文,处理证书和密钥。 9. **...
- 支持多种认证机制,如Basic Auth、Digest Auth等,可以通过`CredentialsProvider`和`AuthSchemeRegistry`配置。 - 对于HTTPS支持,需要配置`SSLContext`和`X509TrustManager`来处理证书和安全策略。 6. **...
4. **认证和安全性**: 对于需要身份验证的网站,HttpClient支持多种认证机制,如Basic Auth、Digest Auth等。 5. **处理Cookie**: 如果网站依赖于Cookie保持会话,HttpClient允许你管理Cookie策略。 总的来说,...
6. **身份验证与安全**:HttpClient支持基本认证、NTLM、Kerberos等多种认证机制。对于HTTPS,可以配置SSLContext和TrustManager以确保安全连接。 7. **Cookie管理**:如果你的HTTP交互涉及Cookie,HttpClient可以...
HttpClient支持多种认证机制、重定向策略、连接管理和时间控制等,使得开发者能够灵活地构建复杂的HTTP交互逻辑。 描述中提到的链接指向了一个ITEYE博客文章,虽然内容没有给出,但通常这类文章会包含如何配置和...
2. **examples** 目录:这个目录提供了使用HttpClient的示例代码,涵盖了各种常见的HTTP操作,如GET、POST、PUT、DELETE等方法,以及处理重定向、认证、cookies、多线程等场景。通过这些示例,开发者可以快速理解...
- **连接策略**:HttpClient允许设置连接策略,如重试机制、超时控制和重定向处理。 3. **请求头和响应头** - **添加请求头**:HttpClient允许添加自定义请求头,例如设置User-Agent、Accept-Encoding等。 - **...