2012-04-18 105 views
7

我不得不使用.NET重新編寫現有的REST API(最初使用Ruby編寫)。從客戶的角度來看,它必須以與舊API完全相同的方式工作 - 即客戶端代碼不需要改變。當前的API需要基本認證。所以叫舊的API,下面完美的作品: -ASP.Net Web API - 授權標題空白

 var wc = new System.Net.WebClient(); 
     var myCache = new CredentialCache(); 
     myCache.Add(new Uri(url), "Basic", new NetworkCredential("XXX", "XXX")); 
     wc.Credentials = myCache; 
     var returnBytes = wc.DownloadData("http://xxxx"); 

(我不得不ommit真實的URL /用戶名/密碼,出於安全考慮等)。

現在我正在使用ASP.Net Web API和MVC4編寫新API。我有一個奇怪的問題,並找不到任何人有完全相同的問題。爲了支持基本身份驗證,我按照這裏的準則:

http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/

有一兩件事,我把代碼爲「鉤在處理程序」,在在Application_Start中的Global.asax.cs文件()事件(沒有解釋,所以我猜)。

無論如何,如果我使用上面的代碼調用我的API(我已經部署在IIS中),授權標頭始終爲空,並且上面的401未授權失敗。但是,如果我使用此代碼手動設置標題,它將正常工作 - 即授權標題現在存在,並且我可以對用戶進行身份驗證。

private void SetBasicAuthHeader(WebClient request, String userName, String userPassword) 
    { 
     string authInfo = userName + ":" + userPassword; 
     authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); 
     request.Headers["Authorization"] = "Basic " + authInfo; 
    } 
    ....... 
    var wc = new System.Net.WebClient(); 
    SetBasicAuthHeader(request, "XXXX", "XXXX"); 
    var returnBytes = wc.DownloadData("http://xxxx"); 

雖然這樣的作品,它沒有對我很好,因爲現有的API的現有用戶不會手動設置的頭。

閱讀基本身份驗證如何工作,初始請求是匿名的,然後客戶端返回401,然後客戶端打算再次嘗試。但是,如果我在代碼中放置了一個斷點,它在Antony的例子中將不會再次觸發代碼。我期待着我的斷點被擊兩次。

任何想法,我可以得到這個工作?

回答

9

你在期待正確的行爲。在初始請求時,System.Net.WebClient不會自動包含授權標頭。它只在適當地被響應挑戰時發送它們,據我所知,它是一個401狀態碼一個正確的WWW-Authenticate頭。有關更多信息,請參見herehere

我假設你的基本身份驗證處理程序沒有返回WWW-Authenticate頭,因此這樣的WebClient甚至不會嘗試在第二個請求上發送憑據。您應該能夠在Fiddler或類似的工具中觀看此視頻。

如果您的處理程序做了這樣的事情,你應該看到WebClient的方式工作:

//if is not authenticated or Authorization header is null 
return base.SendAsync(request, cancellationToken).ContinueWith(task => 
    { 
     var response = task.Result; 
     response.StatusCode = HttpStatusCode.Unauthorized; 
     response.Headers.Add("WWW-Authenticate", "Basic realm=\"www.whatever.com\""); 
     return response; 
    }); 

//else (is authenticated) 
return base.SendAsync(request, cancellationToken); 

正如你注意到,如果包括在每個請求的Authorization頭(就像你在你的另一種方法一樣),然後你的處理程序已經按原樣工作。所以這可能就足夠了 - 它不僅僅適用於以同樣方式運行的WebClient和其他客戶端。

+0

完美 - 它的工作!非常感謝你。 – nickthompson 2012-04-19 06:47:16