问题
DefaultHttpHandler is deprecated, HttpURLConnection does not support NTLM and NTLM seems to be the only well-supported protocol by ASP.NET MCV websites. So, what's left to do?
In our business we use Microsoft. We log in using Microsoft, our webmail is done by Microsoft, and our tablet applications are Android...
Currently I'm working on a project that requires a connection to an ASP.NET entity framework webinterface. This webinterface is hosted on an IIS, configured with Windows Authentication, using NTLM as provider.
The app I'm making has to access this webinterface. So, I ask the users for their username and password, and want to log in on the webinterface. However, Android does not support NTLM at all. I've been looking around, but it seems like this combination is fairly rare. I'd like to know, what are my options?
I am allowed to mess with pretty much anything. The only requrement is that users log in using their Microsoft account, and we'd prefer not using the overly-priced Xamarin. What would you reccomend?
回答1:
Okay so the first thing I did was to import the JCIFS library. Its a jar you download from that link.
The next thing I needed to do was to import the JCIFSEngine class and NTLMSchemeFactory class into your project.
Then finally this method builds your HTTPClient:
//I know it is deprecated but there is no other way to implement NTLM thus far.
private static DefaultHttpClient setupHttpClient (String username, String password) {
DefaultHttpClient httpclient = new DefaultHttpClient();
// register ntlm auth scheme
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
httpclient.getCredentialsProvider().setCredentials(
// Limit the credentials only to the specified domain and port
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
// Specify credentials, most of the time only user/pass is needed
new NTCredentials(username, password, "", "")
);
return httpclient;
}
My connections are done with Retrofit so I just attach this HTTPClient to retrofit using the following line:
retrofitAdapterBuilder.setClient(new ApacheClient(setupHttpClient(username, password)));
This worked for me thus far even-though it is really bad that Android has no native support for this.
EDIT: Adding an Okhttp implementation. This is an old class and we are no longer using it as we decided to drop NTLM support, but it used to work. Please keep in mind that we connect to servers that can have basic/windows/azure authentication so we need to do multiple checks which you might not need to do.
First create a class which implements the Authenticator interface from okhttp. Then in the authenticate() method do the following:
@Override
public Request authenticate(Route route, okhttp3.Response response) throws IOException {
if (response == null || response.headers() == null || response.headers().toString().isEmpty()) {
return null;
}
final List<String> authHeaders = response.headers().values("WWW-Authenticate");
if (authHeaders.contains("NTLM")) {
return response.request().newBuilder().header("Authorization", "NTLM " + mNtlmInitialChallenge).build();
} else if (checkIsBasicAuth(authHeaders)) {
String credentials = mUsername + ":" + mPassword;
final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
return response.request().newBuilder().header("Authorization", basic).build();
}
if (mChallengeSent) {
return null;
} else {
mChallengeSent = true;
String ntlmFinalChallenge = null;
try {
ntlmFinalChallenge = mNtlmEngine.generateType3Msg(mUsername, mPassword, mDomain, "android-device", authHeaders.get(0).substring(5));
} catch (Exception e) {
e.printStackTrace();
}
return response.request().newBuilder().header("Authorization", "NTLM " + ntlmFinalChallenge).build();
}
}
To generate the mNtlmInitialChallenge create the following method:
private String getInitialNtlmChallenge() {
String initialChallenge = null;
try {
initialChallenge = mNtlmEngine.generateType1Msg(null, null);
} catch (Exception e) {
e.printStackTrace();
}
return initialChallenge;
}
The mNtlmEngine class I copied over from the JCIFS library manually so I could remove the dependency.
Some notes:
The code is not the cleanest as this was a POC.
Yes we used the dreaded mVariable notation, we are not using it anymore.
You are going to have to play around with this implementation until it works for you.
To attach the authenticator to okhttp just do
client.authenticator(new NtlmAuthenticator(username, password, ""));
You are probably going to need to implement some failure mechanism.
回答2:
Just do FBA in MCV https://msdn.microsoft.com/en-us/library/ff398049(v=vs.100).aspx
It is well supported.
来源:https://stackoverflow.com/questions/32435086/android-windows-authentication