43

我有一個使用Web API的ASP.NET MVC 4項目。在控制器上,我使用[Authorize]屬性將類設置爲要求授權。對於身份驗證,我正在使用ASP.NET成員資格提供程序,並將我的Web.Config設置爲使用「表單」身份驗證。這裏是我卡在哪裏:ASP.NET MVC 4與成員資格提供者的Web API身份驗證

一切都工作得很好,直到我完成了測試API,我想用[Authorize]屬性來保護控制器,這樣我就可以開始測試用戶身份驗證會員供應商。所以,我火了小提琴手和進行相同的調用將授權:與用戶名的基本屬性:密碼從我的成員資格提供像這樣:

enter image description here

我得到的是401未授權和「驗證」下的響應我得到「沒有WWW-Authenticate Header存在」。然後我意識到API正在尋找一個SHA1編碼密鑰。所以,我火了,從搜索的SHA1發電機,並獲得自己的用戶名散列:密碼和更新我的請求頭,像這樣:

enter image description here

這不工作,要麼,我也得到了相同的結果。此外,我顯然需要某種「共享密​​鑰」與服務器一起使用來解密我的用戶名/密碼。

所以我的問題:

  1. 我如何從服務器獲取這個鍵(或者在這種情況下,IIS虛擬流失VS 2012)。
  2. 如何使用此工具在Fiddler中使用來自ASP.NET成員資格提供程序的用戶名/密碼進行身份驗證呼叫。
  3. 我將如何在我的客戶端應用程序中使用它來進行相同的調用(C#WPF應用程序)。
  4. 當我的HTTP調用與SSL結合使用時,這是否最好?如果不是什麼?

在此先感謝!

回答

67

您可以使用帶有SSL的basic authentication。在服務器端,我們可以寫一個自定義的委託處理程序將通過查詢我們註冊的memebership提供商驗證憑據,如果有效,檢索角色和設定現任校長:

public class BasicAuthenticationMessageHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     var authHeader = request.Headers.Authorization; 

     if (authHeader == null) 
     { 
      return base.SendAsync(request, cancellationToken); 
     } 

     if (authHeader.Scheme != "Basic") 
     { 
      return base.SendAsync(request, cancellationToken); 
     } 

     var encodedUserPass = authHeader.Parameter.Trim(); 
     var userPass = Encoding.ASCII.GetString(Convert.FromBase64String(encodedUserPass)); 
     var parts = userPass.Split(":".ToCharArray()); 
     var username = parts[0]; 
     var password = parts[1]; 

     if (!Membership.ValidateUser(username, password)) 
     { 
      return base.SendAsync(request, cancellationToken); 
     } 

     var identity = new GenericIdentity(username, "Basic"); 
     string[] roles = Roles.Provider.GetRolesForUser(username); 
     var principal = new GenericPrincipal(identity, roles); 
     Thread.CurrentPrincipal = principal; 
     if (HttpContext.Current != null) 
     { 
      HttpContext.Current.User = principal; 
     } 

     return base.SendAsync(request, cancellationToken); 
    } 
} 

我們再註冊此處理在Application_Start

GlobalConfiguration.Configuration.MessageHandlers.Add(
    new BasicAuthenticationMessageHandler() 
); 

現在我們可以有一個API控制器將與[授權]裝飾屬性,以確保只有合法的用戶才能訪問它的行動:

[Authorize] 
public class ValuesController : ApiController 
{ 
    public string Get() 
    { 
     return string.Format("Hello {0}", User.Identity.Name); 
    } 
} 

好了,現在讓我們來看看一個簡單的客戶端:

using System; 
using System.Net; 
using System.Net.Http; 
using System.Net.Http.Headers; 
using System.Text; 

class Program 
{ 
    static void Main() 
    { 
     // since for testing purposes I am using IIS Express 
     // with an invalid SSL certificate I need to desactivate 
     // the check for this certificate. 
     ServicePointManager.ServerCertificateValidationCallback += 
      (sender, certificate, chain, sslPolicyErrors) => true; 

     using (var client = new HttpClient()) 
     { 
      var buffer = Encoding.ASCII.GetBytes("john:secret"); 
      var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer)); 
      client.DefaultRequestHeaders.Authorization = authHeader; 
      var task = client.GetAsync("https://localhost:44300/api/values"); 
      if (task.Result.StatusCode == HttpStatusCode.Unauthorized) 
      { 
       Console.WriteLine("wrong credentials"); 
      } 
      else 
      { 
       task.Result.EnsureSuccessStatusCode(); 
       Console.WriteLine(task.Result.Content.ReadAsAsync<string>().Result); 
      } 
     } 
    } 
} 
+0

達林感謝,這正是我需要的! – CodeAbundance 2012-07-19 06:14:48

+0

控制器方法中的User.Identity.Name'對我來說是空的,'User.Identity.IsAuthenticated'是'false'。我可以在調試器中看到'Thread.CurrentPrincipal'被設置爲消息處理程序中具有正確用戶名和角色的主體。還有'[授權(角色= ...)]'尊重屬性:如果我使用具有錯誤角色的用戶,則會收到未經授權的響應,並且未達到控制器方法。但是'User.Identity'沒有我在消息處理程序中設置的值。你有什麼想法可能是錯誤的? – Slauma 2012-08-19 14:23:15

+0

@Slauma,我無法重現這一點。也許你可以開始一個新的線程一步一步地解釋如何重現問題(當然從一個空的項目開始)。 – 2012-08-19 14:39:35

相關問題