如何在Web Api中使用Api密钥来使用表单身份验证进行服务身份验证
本文关键字:身份验证 Api 服务 表单 密钥 Web | 更新日期: 2023-09-27 18:10:27
我正在使用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);
}
当我调用api时:
[Authorize]
public class TestController : ApiController
{
public string GetLists()
{
return "Weee";
}
}
处理程序找不到X-ApiKey头。
是否有一种方法可以将用户的api密钥添加到http响应头并保持密钥在那里,只要用户登录?有没有其他方法来实现这个功能?
我找到了下面的文章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();
}
和实现接口的类:
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使用authorization属性了:
[Authorize]
public class TestController : ApiController
{
public string Get()
{
return String.Empty;
}
}
这意味着,如果用户没有登录。他不能访问我的api并收到401错误。此外,我可以检索api键,我使用它作为用户ID,在我的代码的任何地方,这使得它非常干净和可读。
我不认为使用cookie是最好的解决方案,因为一些用户可能已经在浏览器中禁用了cookie,但目前我还没有找到更好的方法来进行授权。
从你的代码样本,它似乎不像你在使用Web表单。您可能正在使用表单身份验证?您是否在服务中使用会员资格提供程序来验证用户凭据?
你可以使用HttpClient类,也许它的属性DefaultRequestHeaders或HttpRequestMessage从代码将调用API来设置头。
这里有一些HttpClient的例子:http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client