首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

转: 怎么使用HttpClient认证机制

2013-09-29 
转: 如何使用HttpClient认证机制如何使用HttpClient认证机制本文介绍HttpClient的认证机制,并给出示例代码

转: 如何使用HttpClient认证机制

如何使用HttpClient认证机制
本文介绍HttpClient的认证机制,并给出示例代码。

author: ZJ?07-11-21Blog:?http://zhangjunhd.blog.51cto.com/

本文出自 “子 孑” 博客,请务必保留此出处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认证应答信息传给服务器,即使在某种情况下服务器可能返回认证失败的应答,这样做主要是为了减少连接的建立。使用该机制如下所示:抢先认证模式也提供对于特定目标或代理的缺省认证。如果没有提供缺省的认证信息,则该模式会失效。Httpclient实现的抢先认证遵循rfc2617.?1.2服务器认证的安全方面考虑当需要与不被信任的站点或web应用通信时,应该谨慎使用缺省的认证机制。当启动(activate)抢先认证模式,或者认证中没有明确给出认证域,主机的HttpClient将使用缺省的认证机制去试图获得目标站点的授权。如果你提供的认证信息是敏感的,你应该指定认证域。不推荐将认证域指定为AuthScope.ANY。(只有在debugging情况下,才使用)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中。选择优先级是按插入顺序确定的。?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 GETint status = client.executeMethod(get);// print the status and responseSystem.out.println(status + "\n" + get.getResponseBodyAsString());} finally {// release any connection resources used by the methodget.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 & DigestList<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 responseSystem.out.println(status);System.out.println(httpget.getStatusLine());System.out.println(httpget.getResponseBodyAsString());} finally {// release any connection resources used by the methodhttpget.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 schemeAuthPolicy.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 exampleHttpParams 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// examplereturn null;}public String getRealm() {// this scheme does not use realmsreturn 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 truereturn 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 GETint status = client.executeMethod(httpget);// print the status and responseSystem.out.println(status);System.out.println(httpget.getStatusLine().toString());System.out.println(httpget.getResponseBodyAsString());} finally {// release any connection resources used by the methodhttpget.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);}}}}
?

热点排行