【问题标题】:How to use Api key in Web Api for service authentication using forms authentication如何在 Web Api 中使用 Api 密钥进行使用表单身份验证的服务身份验证
【发布时间】:2013-04-27 02:15:02
【问题描述】:

我正在使用 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 响应标头并将密钥保留在那里,只要用户登录? 还有其他方法可以实现此功能吗?

【问题讨论】:

    标签: c# http asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    我找到了以下文章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 使用 Authorize 属性:

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

    这意味着,如果用户未登录。他无法访问我的 api 并收到 401 错误。此外,我还可以在代码中的任何位置检索用作用户 ID 的 api 密钥,这使得代码非常干净易读。

    我不认为使用 cookie 是最好的解决方案,因为某些用户可能在他们的浏览器中禁用了它们,但目前我还没有找到更好的授权方式。

    【讨论】:

      【解决方案2】:

      从您的代码示例来看,您似乎没有使用 Web 表单。您可能正在使用表单身份验证吗?您是否在服务中使用 Membership Provider 来验证用户凭据?

      您可以使用 HttpClient 类,也可以使用其属性 DefaultRequestHeaders 或来自将调用 API 以设置标头的代码中的 HttpRequestMessage。

      这里有一些HttpClient的例子: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

      【讨论】:

      • 谢谢!你说得对,我的意思是表单身份验证。我编辑了我的问题。我没有使用成员资格提供程序,而是创建了自定义身份验证逻辑。我不能使用 HttpRequestMessage,因为我正在使用 MVC 控制器进行身份验证并返回一个操作结果(或者我不知道使用它的方法)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 1970-01-01
      • 2021-01-22
      • 2017-06-07
      • 2011-12-10
      • 2020-04-11
      相关资源
      最近更新 更多