如何在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响应头并保持密钥在那里,只要用户登录?有没有其他方法来实现这个功能?

如何在Web Api中使用Api密钥来使用表单身份验证进行服务身份验证

我找到了下面的文章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