在使用 iOS 并在没有太多学习曲线的情况下处理身份验证挑战之后,我发现 Windows 身份验证在 Java/Android 中的过程要复杂得多。
我尝试了多种不同的方法,因此无需过多介绍这些方法,我将使用最有效的方法。我现在正在使用为 NTLM 和 ksoap 创建的名为NtlmTransport的类
我现在通过以下方式成功进行身份验证:
NtlmTransport httpTransport = new NtlmTransport();
httpTransport.setCredentials(serverURL, Login.username, Login.password, deviceIp, "DOMAINNAME");
httpTransport.call(SOAP_ACTION, envelope);
如果您查看 NtlmTransport 类,您会看到它从 setupNtlm() 返回以下标头:
- 状态行 HTTP/1.1 200 OK
- 设置 Cache-Control:private, max-age=0
- 设置内容类型:text/html;字符集=utf-8
- 安装服务器:Microsoft-IIS/8.0
- 设置 X-AspNet-版本:4.0.30319
- 设置持久身份验证:true
- 设置 X-Powered-By:ASP.NET
- 设置日期:2013 年 9 月 17 日星期二 20:57:45 GMT
- 设置内容长度:11549
“Persistent-Auth:true 是我目前关心的主要问题。我得到 SoapObjects 就好了,可以从那个连接中获取我需要的数据,但是一旦我尝试访问网络再次服务,这大概可以在成功验证后被击中,我无法使用 HttpTransportSE 访问不同的方法:
private void setSomething() {
xml = null;
final String SOAP_ACTION = "http://this.ismy.org/AWebServiceMethod";
final String METHOD_NAME = "AWebServiceMethod";
final String URL = protocol + "://" + host + ":" + port + "/WebService.asmx";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
envelope.implicitTypes = true;
envelope.setAddAdornments(false);
try
{
HttpTransportSE transport = new HttpTransportSE(URL);
transport.debug = true;
transport.call(SOAP_ACTION, envelope);
xml = transport.responseDump.toString();
Log.d(TAG, xml);
}
catch(SocketException ex)
{
Log.e("SocketException : " , "Error on setSomething() " + ex.getMessage());
}
catch (Exception e)
{
Log.e("Exception : " , "Error on setSomething() " + e.getMessage());
}
}
这一切都可以作为 AsyncTask 的后台任务正常工作,然后将“xml”传递给 XMLPullParser 方法。
这里的主要问题是为什么我会得到:
setSomething() 上的错误未找到身份验证挑战
??
IIS 成功验证用户 200 后,为什么要求我再次进行身份验证?如何坚持第一个经过身份验证的挑战以在 WebService.asmx 中使用我想要的任何方法?如有必要,需要添加/更改哪些标头以创建会话?我缺少什么使整个 NTLM 流程工作并持续超过需要通过身份验证挑战的 WS 方法?
编辑:添加库代码
public static final class JCIFSEngine implements NTLMEngine {
private static final int TYPE_1_FLAGS =
NtlmFlags.NTLMSSP_NEGOTIATE_56 |
NtlmFlags.NTLMSSP_NEGOTIATE_128 |
NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NtlmFlags.NTLMSSP_REQUEST_TARGET;
public String generateType1Msg(final String domain, final String workstation)
throws NTLMEngineException {
final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
return jcifs.util.Base64.encode(type1Message.toByteArray());
}
public String generateType3Msg(final String username, final String password,
final String domain, final String workstation, final String challenge)
throws NTLMEngineException {
Type2Message type2Message;
try {
type2Message = new Type2Message(jcifs.util.Base64.decode(challenge));
} catch (final IOException exception) {
throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
}
final int type2Flags = type2Message.getFlags();
final int type3Flags = type2Flags
& (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
final Type3Message type3Message = new Type3Message(type2Message, Login.password, "",
Login.username, deviceIp, type3Flags);
System.out.println("type3Message: " + type3Message.toByteArray());
return jcifs.util.Base64.encode(type3Message.toByteArray());
}
}
那么“NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN”会导致这个问题吗?我应该为保持活动设置另一个标志吗?此外,我还找到了一个很好的资源来获取 NTLM 标志和更多信息:http: //fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.html