HttpClient fails to authenticate via NTLM on the s

2020-04-30 02:51发布

问题:

Sorry for the long title, but it seems to be the best summary based on what I know so far.

We’re currently working on a Universal App that needs to access some documents on a Sharepoint server via the REST API using NTLM Authentication, which proves to be more difficult than it should be. While we were able to find workarounds for all problems (see below), I don’t really understand what is happening and why they are even necessary. Somehow the HttpClient class seems to behave differently on the phone and on the PC. Here’s what I figured out so far.

I started with this code:

var credentials = new NetworkCredential(userName, password);

var handler = new HttpClientHandler() 
{
    Credentials = credentials
};

var client = new HttpClient(handler);

var response = await client.GetAsync(url);

This works fine in the Windows app, but it fails in the Windows Phone app. The server just returns a 401 Unauthorized status code.

Some research revealed that you need to provide a domain to the NetworkCredential class.

var credentials = new NetworkCredential(userName, password, domain);

This works on both platforms. But why is the domain not required on Windows?

The next problem appears when you try to do multiple requests:

var response1 = await client.GetAsync(url);
var response2 = await client.GetAsync(url);

Again, this works just fine in the Windows app. Both requests return successfully:

And again, it fails on the phone. The first request returns without problems:

Strangely any consecutive requests to the same resource fail, again with status code 401.

This problem has been encountered before, but there doesn’t seem to be a solution yet.

An answer in the second thread suggests that there’s something wrong with the NTLM handshake. But why only the second time? Also, it seems to be a problem of the HttpClient class, because the following code works without problems on both platforms:

var request3 = WebRequest.CreateHttp(url);
request3.Credentials = credentials;

var response3 = await request3.GetResponseAsync();

var request4 = WebRequest.CreateHttp(url);
request4.Credentials = credentials;

var response4 = await request4.GetResponseAsync();

So the problem only appears:

  • on Windows Phone. The same code in a Windows App works.
  • when connecting to Sharepoint. Accessing another site with NTLM authentication works on both platforms.
  • when using HttpClient. Using WebRequest, it works.

So while I'm glad that I at least found some way to make it work, I’d really like to know what’s so special about this combination and what could be done to make it work?

回答1:

Hi Daniel at the same problem when I do my sync, because windows phone had a lot of problems with cache, finallt I could solve with add headers. Also I think so it's good idea that you use the timeout because it's a loooong response you can wait a lot of time... And the other good way to work it's use "using", it's similar that use ".Dispose()". Now I show you the code:

 var request3 = WebRequest.CreateHttp(url);
 request3.Credentials = credentials;
 request.ContinueTimeout = 4000; //4 seconds

 //For solve cache problems
 request.Headers["Cache-Control"] = "no-cache";
 request.Headers["Pragma"] = "no-cache";

 using(httpWebResponse response3 = (httpWebResponse) await request3.GetResponseAsync()){
      if (response3.StatusCode == HttpStatusCode.OK)
      {
          //Your code...
      }
 }

 var request4 = WebRequest.CreateHttp(url);
 request4.Credentials = credentials;
 request.ContinueTimeout = 4000; //4 seconds

 //For solve cache problems
 request.Headers["Cache-Control"] = "no-cache";
 request.Headers["Pragma"] = "no-cache";

 using(httpWebResponse response4 = (httpWebResponse) await request4.GetResponseAsync()){
      if (response4.StatusCode == HttpStatusCode.OK)
      {
          //Your code...
      }
 }

I wait that my code can help you. Thanks and good luck!