2013-04-22 286 views
7

我正在使用MVC 4 Web Api,並且希望用戶在使用我的服務之前進行身份驗證。如何在Web API中使用Api密鑰進行使用表單身份驗證的服務身份驗證

我已經實現了一個授權消息處理程序,工作得很好。

public class AuthorizationHandler : DelegatingHandler 
{ 
    private readonly AuthenticationService _authenticationService = new AuthenticationService(); 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     IEnumerable<string> apiKeyHeaderValues = null; 
     if (request.Headers.TryGetValues("X-ApiKey", out apiKeyHeaderValues)) 
     { 
      var apiKeyHeaderValue = apiKeyHeaderValues.First(); 

      // ... your authentication logic here ... 
      var user = _authenticationService.GetUserByKey(new Guid(apiKeyHeaderValue)); 

      if (user != null) 
      { 

       var userId = user.Id; 

       var userIdClaim = new Claim(ClaimTypes.SerialNumber, userId.ToString()); 
       var identity = new ClaimsIdentity(new[] { userIdClaim }, "ApiKey"); 
       var principal = new ClaimsPrincipal(identity); 

       Thread.CurrentPrincipal = principal; 
      } 
     } 

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

問題是,我使用表單身份驗證。

[HttpPost] 
    public ActionResult Login(UserModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      var user = _authenticationService.Login(model); 
      if (user != null) 
      { 
       // Add the api key to the HttpResponse??? 
      } 
      return View(model); 
     } 

     return View(model); 
    } 

當我打電話給我的API:

[Authorize] 
public class TestController : ApiController 
{ 
    public string GetLists() 
    { 
     return "Weee"; 
    } 
} 

處理程序無法找到X-ApiKey頭。

只要用戶登錄,是否有方法將用戶的api密鑰添加到http響應頭並保留密鑰? 是否有另一種實現此功能的方式?

回答

2

我發現下面的文章http://www.asp.net/web-api/overview/working-with-http/http-cookies 使用它,我配置了我AuthorizationHandler使用Cookie:

public class AuthorizationHandler : DelegatingHandler 
{ 
    private readonly IAuthenticationService _authenticationService = new AuthenticationService(); 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     var cookie = request.Headers.GetCookies(Constants.ApiKey).FirstOrDefault(); 
     if (cookie != null) 
     { 
      var apiKey = cookie[Constants.ApiKey].Value; 
      try 
      { 
       var guidKey = Guid.Parse(apiKey); 

       var user = _authenticationService.GetUserByKey(guidKey); 
       if (user != null) 
       { 

        var userIdClaim = new Claim(ClaimTypes.Name, apiKey); 
        var identity = new ClaimsIdentity(new[] { userIdClaim }, "ApiKey"); 
        var principal = new ClaimsPrincipal(identity); 

        Thread.CurrentPrincipal = principal; 

       } 
      } 
      catch (FormatException) 
      { 
      } 
     } 

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

我配置我的登錄作用的結果:

[HttpPost] 
    public ActionResult Login(LoginModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      var user = _authenticationService.Login(model); 
      if (user != null) 
      { 
       _cookieHelper.SetCookie(user); 

       return RedirectToAction("Index", "Home"); 
      } 

      ModelState.AddModelError("", "Incorrect username or password"); 
      return View(model); 
     } 

     return View(model); 
    } 

它裏面我使用CookieHelper,我創建的。它由一個接口:

public interface ICookieHelper 
{ 
    void SetCookie(User user); 

    void RemoveCookie(); 

    Guid GetUserId(); 
} 

和A類實現接口:

public class CookieHelper : ICookieHelper 
{ 
    private readonly HttpContextBase _httpContext; 

    public CookieHelper(HttpContextBase httpContext) 
    { 
     _httpContext = httpContext; 
    } 

    public void SetCookie(User user) 
    { 
     var cookie = new HttpCookie(Constants.ApiKey, user.UserId.ToString()) 
     { 
      Expires = DateTime.UtcNow.AddDays(1) 
     }; 

     _httpContext.Response.Cookies.Add(cookie); 
    } 

    public void RemoveCookie() 
    { 
     var cookie = _httpContext.Response.Cookies[Constants.ApiKey]; 
     if (cookie != null) 
     { 
      cookie.Expires = DateTime.UtcNow.AddDays(-1); 
      _httpContext.Response.Cookies.Add(cookie); 
     } 
    } 

    public Guid GetUserId() 
    { 
     var cookie = _httpContext.Request.Cookies[Constants.ApiKey]; 
     if (cookie != null && cookie.Value != null) 
     { 
      return Guid.Parse(cookie.Value); 
     } 

     return Guid.Empty; 
    } 
} 

通過具有這種結構,現在我可以使用授權屬性爲我ApiControllers:

[Authorize] 
public class TestController : ApiController 
{ 
    public string Get() 
    { 
     return String.Empty; 
    } 
} 

這意味着,如果用戶未登錄,他將無法訪問我的api並收到401錯誤。此外,我可以檢索我用作用戶ID的api密鑰,在我的代碼中的任何地方,這使得它非常乾淨和可讀。

我不認爲使用cookie是最好的解決方案,因爲某些用戶可能已經禁用了他們的瀏覽器,但目前我還沒有找到更好的方法來執行授權。

1

從您的代碼示例看來,它似乎不像您使用Web窗體。你可能使用表單身份驗證?您是否在服務中使用了成員資格提供程序來驗證用戶憑據?

您可以使用HttpClient類,也可以使用它的屬性DefaultRequestHeaders或來自將調用API設置標頭的代碼的HttpRequestMessage。

這裏有HttpClient的一些例子: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

+0

謝謝!你是對的我的意思是表單身份驗證。我編輯了我的問題。我沒有使用成員資格提供程序,而是創建了自定義身份驗證邏輯。 我不能使用HttpRequestMessage,因爲我正在使用MVC控制器進行身份驗證,並返回一個Action Result(或者我不知道如何使用它)。 – 2013-04-26 18:18:10

相關問題