2013-10-21 72 views
3

我的代碼正在對需要基本身份驗證的Web服務URL進行HTTP GET。C#HttpClient重定向後未發送基本身份驗證

我已經使用HttpClientHttpClientHandler實現了此功能,該功能定義了Credentials屬性。

這一切都完美..除了我的使用情況之一,我正在進行身份驗證GET: http://somedomain.com重定向到http://www.somedomain.com

看來,HttpClientHandler在重定向期間清除了認證頭。我怎樣才能防止這一點?無論重定向如何,我都希望發送憑據。

這是我的代碼:

// prepare the request 
var request = new HttpRequestMessage(method, url); 
using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(username, password) , PreAuthenticate = true }) 
using (var client = new HttpClient(handler)) 
{ 
    // send the request 
    var response = await client.SendAsync(request); 

注:這是一個相關的問題: Keeping HTTP Basic Authentification alive while being redirected 但自從我使用不同類發出請求,有可能是一個更好的,更具體的解決方案

+0

附註,我認爲設計的行爲在這種情況下是沒有意義的。我將憑據設置爲客戶端的一部分,而不是根據特定的URI(請求)。由於同一個客戶端可以執行多個請求,並且授權將被髮送,而不管他們的URI如何,所以這非常愚蠢 – talkol

回答

2

默認的HttpClientHandler在封面下使用相同的HttpWebRequest基礎結構。而不是分配一個NetworkCredential到Credentials屬性,創建一個CredentialCache並分配它。

這是我用來代替AutoRedirect和一點異步/等待仙塵它可能會更漂亮和更可靠。

public class GlobalRedirectHandler : DelegatingHandler { 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { 
     var tcs = new TaskCompletionSource<HttpResponseMessage>(); 

     base.SendAsync(request, cancellationToken) 
      .ContinueWith(t => { 
       HttpResponseMessage response; 
       try { 
        response = t.Result; 
       } 
       catch (Exception e) { 
        response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable); 
        response.ReasonPhrase = e.Message; 
       } 
       if (response.StatusCode == HttpStatusCode.MovedPermanently 
        || response.StatusCode == HttpStatusCode.Moved 
        || response.StatusCode == HttpStatusCode.Redirect 
        || response.StatusCode == HttpStatusCode.Found 
        || response.StatusCode == HttpStatusCode.SeeOther 
        || response.StatusCode == HttpStatusCode.RedirectKeepVerb 
        || response.StatusCode == HttpStatusCode.TemporaryRedirect 

        || (int)response.StatusCode == 308) 
       { 

        var newRequest = CopyRequest(response.RequestMessage); 

        if (response.StatusCode == HttpStatusCode.Redirect 
         || response.StatusCode == HttpStatusCode.Found 
         || response.StatusCode == HttpStatusCode.SeeOther) 
        { 
         newRequest.Content = null; 
         newRequest.Method = HttpMethod.Get; 

        } 
        newRequest.RequestUri = response.Headers.Location; 

        base.SendAsync(newRequest, cancellationToken) 
         .ContinueWith(t2 => tcs.SetResult(t2.Result)); 
       } 
       else { 
        tcs.SetResult(response); 
       } 
      }); 

     return tcs.Task; 
    } 

    private static HttpRequestMessage CopyRequest(HttpRequestMessage oldRequest) { 
     var newrequest = new HttpRequestMessage(oldRequest.Method, oldRequest.RequestUri); 

     foreach (var header in oldRequest.Headers) { 
      newrequest.Headers.TryAddWithoutValidation(header.Key, header.Value); 
     } 
     foreach (var property in oldRequest.Properties) { 
      newrequest.Properties.Add(property); 
     } 
     if (oldRequest.Content != null) newrequest.Content = new StreamContent(oldRequest.Content.ReadAsStreamAsync().Result); 
     return newrequest; 
    } 
} 
+0

CredentialCache的問題是我需要過早知道URI後重定向 - 我不知道。 API端點可由用戶配置,這些用戶可能會忘記提供www,或決定某天購買新域。 – talkol

+1

@talkol好的。然後關閉autoredirect並編寫自己的消息處理程序來執行重定向。這很容易做到。只需注意將這些憑據發送到任意站點的安全問題。 –

+0

耶謝謝,這就是我最終做的。與異步等待仙塵當然;) – talkol