【问题标题】:How do I pass objects between `HandleAuthenticateAsync` and `HandleChallengeAsync` in my custom `AuthenticationHandler`?如何在自定义“AuthenticationHandler”中的“HandleAuthenticateAsync”和“HandleChallengeAsync”之间传递对象?
【发布时间】:2019-10-08 21:21:39
【问题描述】:

我无法找到正确的方法将对象从我的自定义身份验证代码所在的 HandleAuthenticateAsync 传递到 HandleChallengeAsync 回调,我在其中处理身份验证失败并设置响应状态代码和正文。

如果身份验证失败,我想返回一个 JSON 对象,该对象在响应正文中包含有关身份验证失败原因的一些信息。

在我的处理程序代码中,我想在HandleChallengeAsync 方法中序列化来自results 的一些值:

public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
{
    public const string ApiKeyHeaderName = "X-API-KEY";

    public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { }

    // The authentication handler that gets call for every request (including `[AllowAnonymous]`
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        Request.Headers.TryGetValue(Options.ApiKeyHeaderName, out var apiKeyHeaderValues);
        var key = apiKeyHeaderValues.FirstOrDefault();

        var results = await new AuthenticateApiKeyQuery(key).Results();

        if (results.HasErrors())
            return AuthenticateResult.Fail("Useless message that doesn't go anywhere");

        return Success(results.Value);
    }

    // the callback that gets called for any `[Authorize]` actions
    override protected async Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        var errors = new { }; // I want `errors` to come from the `result` object above
        Context.Response.StatusCode = 401;
        Context.Response.ContentType = "application/json";
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(errors);
        await Context.Response.Body.WriteAsync(System.Text.Encoding.UTF8.GetBytes(json));
    }

    // Method that sent up the identity/claim etc
    private AuthenticateResult Success(ApiKey apiKey)
    {
        var claims = new List<Claim>()
        {
            new Claim(ClaimTypes.NameIdentifier, apiKey.ID.ToString()),
            new Claim(ClaimTypes.Name, apiKey.Description),
        };

        var identity = new ClaimsIdentity(claims, Options.AuthenticationType);
        var identities = new List<ClaimsIdentity> { identity };
        var principal = new ClaimsPrincipal(identities);
        var ticket = new AuthenticationTicket(principal, Options.AuthenticationScheme);

        return AuthenticateResult.Success(ticket);
    }

我最初的尝试是使用 HandleAuthenticateAsync 方法设置 401 和响应正文。这不起作用,因为身份验证处理程序也会为带有[AllowAnonymous] 标记的操作运行。结果是响应将是 401,并且是序列化的 JSON,而不是操作设置的状态和响应。而HandleChallengeAsync 仅在身份验证失败且操作需要授权时调用。

这不是最容易导航的代码,但据我所知,PolicyEvalulator 调用AuthenticationHandler,然后调用我的自定义HandleAuthenticateAsync。我返回的AuthenticateResult 然后被PolicyEvalulator 吞噬,所以我不能用它来保存任何值以供以后处理。我还没有弄清楚我的自定义 HandleChallengeAsync 是什么,但此时 AuthenticateResult 已经被吞没了。

【问题讨论】:

    标签: authentication asp.net-web-api


    【解决方案1】:

    我遇到了类似的问题,身份验证处理程序是瞬态范围的,您可以在自定义处理程序类中声明一个对象类型属性,该属性将在 HandleChallengeAsync 方法中可用。

    【讨论】:

      猜你喜欢
      • 2018-05-18
      • 1970-01-01
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多