Can I make HttpWebRequest include windows credenti

2019-04-04 15:05发布

问题:

My app communicates with an internal web API that requires authentication.

When I send the request I get the 401 challenge as expected, the handshake occurs, the authenticated request is re-sent and everything continues fine.

However, I know that the auth is required. Why do I have to wait for the challenge? Can I force the request to send the credentials in the first request?

My request generation is like this:

   private static HttpWebRequest BuildRequest(string url, string methodType)
   {
       var request = HttpWebRequest.CreateHttp(url);
       request.PreAuthenticate = true;
       request.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
       request.Credentials = CredentialCache.DefaultNetworkCredentials;
       request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
       request.ContentType = CONTENT_TYPE;
       request.Method = methodType;
       request.UserAgent = BuildUserAgent();
       return request;
   }

Even with this code, the auth header isn't included in the initial request.

I know how to include the auth info with basic.... what I want to do is to use Windows Auth of the user executing the app (so I can't store the password in a config file).

UPDATE I also tried using a HttpClient and its own .Credentials property with the same result: no auth header is added to the initial request.

The only way I could get the auth header in was to hack it in manually using basic authentication (which won't fly for this use-case)

回答1:

Ntlm is a challenge/response based authentication protocol. You need to make the first request so that the server can issue the challenge then in the subsequent request the client sends the response to the challenge. The server then verifies this response with the domain controller by giving it the challenge and the response that the client sent. Without knowing the challenge you can't send the response which is why 2 requests are needed.

Basic authentication is password based so you can short circuit this by sending the credentials with the first request but in my experience this can be a problem for some servers to handle.

More details available here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378749(v=vs.85).aspx



回答2:

I'm not 100% sure, but I suspect that there is no way around this; it's simply the way HttpWebRequest works.

In the online .NET source, function DoSubmitRequestProcessing which is here, you can see this comment just after the start of the function, line 1731:

        // We have a response of some sort, see if we need to resubmit
        // it do to authentication, redirection or something
        // else, then handle clearing out state and draining out old response.

A little further down (line 1795) (some lines removed for brevity)

if (resubmit)
{   
   if (CacheProtocol != null && _HttpResponse != null) CacheProtocol.Reset();
   ClearRequestForResubmit(ntlmFollowupRequest);
   ...
}

And in ClearRequestForResubmit line 5891:

// We're uploading and need to resubmit for Authentication or Redirect.

and then (Line 5923):

// The second NTLM request is required to use the same connection, don't close it
     if (ntlmFollowupRequest) {....}

To my (admittedly n00bish) eyes these comments seem to indicate that the developers decided to follow the "standard" challenge-response protocol for NTML/Kerberos and not include any way of sending authentication headers up-front.



回答3:

Setting PreAuthenticate is what you want, which you are doing. The very first request will still do the handshake but for subsequent requests it will automatically send the credentials (based on the URL being used). You can read up on it here: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.preauthenticate(v=vs.110).aspx.