Android 使用DefaultHttpClient进行抢占式身份验证

Android 使用DefaultHttpClient进行抢占式身份验证,android,authorization,ntlm,apache-httpclient-4.x,preemptive,Android,Authorization,Ntlm,Apache Httpclient 4.x,Preemptive,我想使用NTLM为DefaultHttpClient实现抢占式身份验证。我找到了一个库,它可以正常进行身份验证 但我无法想象如何通过抢占式身份验证实现这一点。我发现这个问题很酷: 对我的问题来说不是完美的,但这是个好主意。因此,我尝试使用NTLMSchemeFactory创建AuthScheme的一个新实例,它为我提供了authenticate函数 NTCredentials ntc = new NTCredentials("example.com/user:pwd"); httpPost.ad

我想使用NTLM为DefaultHttpClient实现抢占式身份验证。我找到了一个库,它可以正常进行身份验证

但我无法想象如何通过抢占式身份验证实现这一点。我发现这个问题很酷:

对我的问题来说不是完美的,但这是个好主意。因此,我尝试使用
NTLMSchemeFactory
创建
AuthScheme
的一个新实例,它为我提供了
authenticate
函数

NTCredentials ntc = new NTCredentials("example.com/user:pwd");
httpPost.addHeader(new NTLMScheme(new JCIFSEngine()).authenticate(ntc, httpPost));
调用此函数时,我将得到一个异常:

org.apache.http.auth.AuthenticationException:意外状态:未初始化

我怎样才能解决这个问题

POST/login/HTTP/1.1
内容长度:21
内容类型:application/x-www-form-urlencoded
主持人:example.com
连接:保持活力
数据=。。。
HTTP/1.1 401未经授权
内容类型:text/html
服务器:Microsoft IIS/7.5
WWW:协商
WWW:NTLM
X-Powered-By:ASP.NET
日期:2012年12月12日星期三14:36:26 GMT
内容长度:1344
很多数据。。。
POST/login/HTTP/1.1
内容长度:21
内容类型:application/x-www-form-urlencoded
主持人:example.com
连接:保持活力
授权:NTLM AAABBCCC…FFF==
数据=。。。

我认为第一个请求毫无用处。

NTLM身份验证不能先发制人地执行。这是一个涉及多(3)个消息交换的复杂方案。

我的解决方案如下:

public class PreemptiveNTLMHeader implements Header {
    private HttpRequest request;
    private NTCredentials ntc;

    public PreemptiveNTLMHeader(HttpRequest request, NTCredentials ntc) {
        this.request = request;
        this.ntc = ntc;
    }

    /* (non-Javadoc)
     * @see org.apache.http.Header#getName()
     */
    public String getName() {
        return "Authorization";
    }

    /* (non-Javadoc)
     * @see org.apache.http.Header#getValue()
     */
    public String getValue() {
        request.removeHeader(this);
        try {
            return "NTLM " + new JCIFSEngine().generateType1Msg(ntc.getDomain(), ntc.getWorkstation());
        } catch(NTLMEngineException e) {
            return "Failed";
        }
    }

    /* (non-Javadoc)
     * @see org.apache.http.Header#getElements()
     */
    public HeaderElement[] getElements() throws ParseException {
        return null;
    }
}
使用此用法:

NTCredentials ntc = new NTCredentials("example.com/user:password");
httpPost.addHeader(new PreemptiveNTLMHeader(httpPost, ntc));

因此,DefaultHttpClient将发送一个跳过初始请求的
授权:NTLM AAA…
头。首次使用此标头后,此标头会删除自身,以避免此虚拟标头覆盖真实的身份验证过程。这对我来说很有用。

但是第一个电话真的没用,没有challange回应或类似的东西。请参阅我的更新。握手始终由NTLM服务器通过询问客户端来启动。请随意查阅规范。我没有阅读规范,但我看到了沟通,基于这一知识,我认为客户从一种用于chellange响应验证的盐开始。到目前为止,我认为我可以跳过服务器告诉我他支持NTLM的部分。鉴于NTLM是一个有状态的方案,尝试以这种奇怪的方式“优化”它可能不会有任何效果,但尝试并没有坏处。我找到了一种方法,看看我自己的答案:-)
NTCredentials ntc = new NTCredentials("example.com/user:password");
httpPost.addHeader(new PreemptiveNTLMHeader(httpPost, ntc));