2013-04-22 15 views
7

私はMVC 4 Web APIを使用しており、サービスを使用する前にユーザーを認証します。フォーム認証を使用したサービス認証のためにWeb ApiでApi keyを使用する方法

私は認可メッセージハンドラを実装しました。これはうまく動作します。

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ヘッダーを見つけることができません。

ユーザーがログインしている限り、http応答ヘッダーにユーザーのapiキーを追加し、そこにキーを保持する方法はありますか? この機能を実装する別の方法はありますか?

答えて

2

私はクッキーを使用するために私のAuthorizationHandlerを設定し、それを使用して、次の資料http://www.asp.net/web-api/overview/working-with-http/http-cookies が見つかりました:

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 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のために承認属性を使用することができます:

public interface ICookieHelper 
{ 
    void SetCookie(User user); 

    void RemoveCookie(); 

    Guid GetUserId(); 
} 

およびインターフェースを実装するクラス:それはインターフェイスで構成されてい

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

これは、ユーザーがログインしていない場合、彼は私のAPIにアクセスすることができず、401エラーを受け取ることを意味します。また、コード内のどこにでもユーザーIDとして使用するAPIキーを取得することができ、非常にきれいで読みやすいものになります。

一部のユーザーがブラウザで無効にしている可能性がありますが、現在のところ、認証を行うためのより良い方法が見つからないため、Cookieを使用するのが最適なソリューションではないと思います。

1

コードサンプルから、Webフォームを使用しているようではありません。フォーム認証を使用している可能性がありますか?サービス内のメンバーシッププロバイダを使用してユーザーの資格情報を検証していますか?

ヘッダーを設定するAPIを呼び出すコードから、HttpClientクラスとそのプロパティDefaultRequestHeadersまたはHttpRequestMessageを使用できます。

ここでのHttpClientのいくつかの例があります。 http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

+0

ありがとうございます!あなたは正しいです、私はフォーム認証を意味しています。私は私の質問を編集しました。私はメンバーシッププロバイダを使用していませんが、代わりにカスタム認証ロジックを作成しました。 HttpRequestMessageを使用することはできません。なぜなら、私はMVC Controllerを使用して認証を行い、アクション結果を返すため(または私はそれを使用する方法がわかりません)。 –

関連する問題