2013-04-22 14 views
7

Sto utilizzando MVC 4 Web Api e voglio che gli utenti vengano autenticati, prima di utilizzare il mio servizio.Come utilizzare la chiave Api in Web Api per l'autenticazione del servizio utilizzando l'autenticazione moduli

Ho implementato un gestore di messaggi di autorizzazione, che funziona bene.

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); 
    } 
} 

Il problema è che utilizzo l'autenticazione dei moduli.

[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); 
    } 

Quando chiamo il mio api:

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

Il conduttore non riesce a trovare l'intestazione X-apikey.

C'è un modo per aggiungere la chiave api dell'utente all'intestazione della risposta http e mantenere la chiave lì, purché l'utente abbia effettuato l'accesso? Esiste un altro modo per implementare questa funzionalità?

risposta

2

ho trovato il seguente articolo http://www.asp.net/web-api/overview/working-with-http/http-cookies Usandolo Ho configurato il mio AuthorizationHandler di utilizzare i 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); 
    } 
} 

Ho configurato il mio login risultato azione:

[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); 
    } 

suo interno sto usando la CookieHelper, che ho creato. Si compone di un'interfaccia:

public interface ICookieHelper 
{ 
    void SetCookie(User user); 

    void RemoveCookie(); 

    Guid GetUserId(); 
} 

E una classe che implementa l'interfaccia:

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; 
    } 
} 

Avendo questa configurazione, ora posso utilizzare l'attributo Autorizza per i miei ApiControllers:

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

Ciò significa che se l'utente non ha effettuato l'accesso. Non può accedere alla mia API e riceve un errore 401. Inoltre posso recuperare la chiave API, che uso come ID utente, ovunque nel mio codice, che lo rende molto pulito e leggibile.

non credo che l'utilizzo di cookie è la soluzione migliore, come qualche utente può averli disabilitato nel proprio browser, ma al momento non ho trovato un modo migliore per fare l'autorizzazione.

1

Dal tuo codice di esempio non sembra che tu stia utilizzando Web Forms. Potresti usare l'autenticazione basata su form? Stai utilizzando il provider di appartenenza all'interno del tuo servizio per convalidare le credenziali dell'utente?

È possibile utilizzare la classe HttpClient e la relativa proprietà DefaultRequestHeaders o HttpRequestMessage dal codice che chiamerà l'API per impostare le intestazioni.

Qui ci sono alcuni esempi di HttpClient: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

+0

Grazie! Hai ragione intendevo l'autenticazione basata su moduli. Ho modificato la mia domanda. Non sto utilizzando un provider di appartenenze, ma ho creato una logica di autenticazione personalizzata. Non riesco a utilizzare HttpRequestMessage, perché eseguo l'autenticazione tramite MVC Controller e restituisco un risultato di azione (o non conosco un modo per usarlo). –

Problemi correlati