我正在使用MVC 4 Web 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); }
当我打电话给我的时候:
[Authorize] public class TestController : ApiController { public string GetLists() { return "Weee"; } }
处理程序找不到X-ApiKey标头.
解决方法
我找到了以下文章
http://www.asp.net/web-api/overview/working-with-http/http-cookies
使用它我配置我的AuthorizationHandler使用cookie:
使用它我配置我的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(); }
以及实现接口的类:
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属性:
[Authorize] public class TestController : ApiController { public string Get() { return String.Empty; } }
这意味着,如果用户没有登录.他无法访问我的api并收到401错误.此外,我可以在我的代码中的任何位置检索api密钥,我将其用作用户ID,这使得它非常干净和可读.
我不认为使用cookie是最好的解决方案,因为有些用户可能已经在浏览器中禁用了它们,但目前我还没有找到更好的方法来进行授权.