c# - 如何在 Web Api 中使用 Api key 使用表单例份验证进行服务身份验证

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

我正在使用 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 header 。

有没有一种方法可以将用户的 api key 添加到 http 响应 header 中,并在用户登录后将 key 保存在那里? 是否有另一种方法来实现此功能?

最佳答案

我找到了以下文章 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。它由一个接口(interface)组成:

public interface ICookieHelper
{
    void SetCookie(User user);

    void RemoveCookie();

    Guid GetUserId();
}

还有一个实现接口(interface)的类:

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 key ,这使得它非常干净和可读。

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

关于c# - 如何在 Web Api 中使用 Api key 使用表单例份验证进行服务身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16157586/

相关文章:

javascript - 使用 JINT 从 javascript 文件读取 JSON 对象

c# - twain 问题 : is it possible to scan just one document from feeder?

c# - WebClient 无法从本地主机下载字符串

debugging - 如何查看我的 HTTP 帖子?

http - 为什么我看不到 HttpUtility.ParseQueryString 方法?

c# - 在 WCF RESTful 服务中访问请求主体

c# - 为什么 viewbag 值不传回 View ?

c# - 尝试从空集合中进行选择时的 LINQ 查询问题

c# - 将 WebApi.HelpPage 添加到 webApi 项目后出现 StructureMap 异常

c# - ASP.NET MVC HtmlHelper Razor 语法