有什么方法可以通过HttpURLConnection实现NTLM身份验证?目前,我已经使用DefaultHttpClient和JCIFSEngine实现了身份验证方案. (我的灵感是:Android: NTLM Authentication, ksoap, and persistent connections)
但是自从Android 6 Apache HTTP Client Removal以来,除了在应用gradle文件中添加useLibrary’org.apache.http.legacy’之外,我一直在寻找解决方案,原因是我想改用HttpURLConnection类来改进代码.如文档所述,此API效率更高,因为它通过透明压缩和响应缓存减少了网络使用,并最大程度地降低了功耗.
解决方法:
仅当添加库jcifs时,HttpURLConnection才能与NTLM一起使用.
这个例子适用于最新的jcifs-1.3.18:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnkNownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.impl.auth.NTLMEngineException;
public class TestNTLMConnection {
public static void main(String[] args) throws UnkNownHostException, IOException, NTLMEngineException {
// Method 1 : authentication in URL
jcifs.Config.registerSmbURLHandler();
URL urlRequest = new URL("http://domain%5Cuser:pass@127.0.0.1/");
// or Method 2 : authentication via System.setproperty()
// System.setProperty("http.auth.ntlm.domain", "domain");
// System.setProperty("jcifs.smb.client.domain", "domain");
// System.setProperty("jcifs.smb.client.username", "user");
// System.setProperty("jcifs.smb.client.password", "pass");
// Not verified // System.setProperty("jcifs.netbios.hostname", "host");
// System.setProperty("java.protocol.handler.pkgs", "jcifs");
// URL urlRequest = new URL("http://127.0.0.1:8180/simulate_get.PHP");
HttpURLConnection conn = (HttpURLConnection) urlRequest.openConnection();
StringBuilder response = new StringBuilder();
try {
InputStream stream = conn.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String str = "";
while ((str = in.readLine()) != null) {
response.append(str);
}
in.close();
System.out.println(response);
} catch(IOException err) {
System.out.println(err);
} finally {
Map<String, String> msgResponse = new HashMap<String, String>();
for (int i = 0;; i++) {
String headerName = conn.getHeaderFieldKey(i);
String headerValue = conn.getHeaderField(i);
if (headerName == null && headerValue == null) {
break;
}
msgResponse.put(headerName == null ? "Method" : headerName, headerValue);
}
System.out.println(msgResponse);
}
}
}
警告:jcifs会忽略您使用该库定义的connectTimeout和readTimeout,这就是当主机不响应时,连接需要经过一段时间才能断开的原因.使用我在this SO thread中描述的代码来避免此错误.