2013-04-22 210 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

相关问题