0

我在我的 .NET Core API 中使用添加多个 Jwt 承载进行了多重身份验证,假设我有Schema1Schema2并且Schema3.

我也在使用Ocelot来管理请求。在每个路由的 Ocelot 配置中,我可以声明一个且只有一个身份验证类型(模式名称)。但是在某些情况下,我需要为每个路由提供多个身份验证支持。(我需要使用 或 中的任何一个来验证请求Schema1)。Schema2Schema3

但是由于 Ocelot 只是让我添加一个模式名称,因此我必须将这 3 个模式合并为 1 个模式。

所以基本问题是:我如何定义一个身份验证模式(SchemaX),它通过Schema1orSchema2或 or进行身份验证Schema3?任何想法?

4

2 回答 2

0

这很简单,如果有人在寻找,我会在这里回答:

基本上只需要定义一个自定义 AuthenticationHandler

public class DynamicAuthenticationOptions : AuthenticationSchemeOptions
{
}
public class DynamicAuthenticationHandler : AuthenticationHandler<DynamicAuthenticationOptions>
{

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

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
            return Task.FromResult(AuthenticateResult.Fail("Unauthorized"));

        string authorizationHeader = Request.Headers["Authorization"];
        if (string.IsNullOrEmpty(authorizationHeader))
            return Task.FromResult(AuthenticateResult.Fail("Unauthorized"));

        if (!authorizationHeader.StartsWith("bearer", StringComparison.OrdinalIgnoreCase))
            return Task.FromResult(AuthenticateResult.Fail("Unauthorized"));

        var token = authorizationHeader.Substring("bearer".Length).Trim();

        IEnumerable<Claim> claims;

        foreach (var validMergedSchema in validMergedSchemas)
        {
            if (IsTokenValid(token, validMergedSchema, out claims))
            {
                var identity = new ClaimsIdentity(claims, Scheme.Name);
                var principal = new System.Security.Principal.GenericPrincipal(identity, null);
                var ticket = new AuthenticationTicket(principal, Scheme.Name);
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        }

        return Task.FromResult(AuthenticateResult.Fail("Unauthorized"));

    }

    private bool IsTokenValid(string tokenStr, string schema, out IEnumerable<Claim> claims)
    {
        claims = null;

        switch (schema.ToLower())
        {
            case "schema1":
                return IsTokenValidBySchema1(tokenStr, out claims);

            case "schema2":
                return IsTokenValidBySchema2(tokenStr, out claims);

            case "schema3":
                return IsTokenValidBySchema3(tokenStr, out claims);

            default:
                return false;
        }

    }
}
于 2020-03-26T15:43:41.553 回答
0

您可以尝试创建自定义 AuthorizeFilter 以允许像这里这样的多个身份验证模式, 或者编写一个自定义中间件来检查来自 http 上下文的 url 路由并手动调用AuthenticateAsync()并创建一个ClaimsPrincipal包含您需要的所有身份,例如:

app.UseAuthentication();
app.Use(async (context, next) =>
{
  var principal = new ClaimsPrincipal();

  var result1 = await context.AuthenticateAsync("MyScheme");
  if (result1?.Principal != null)
  {
      principal.AddIdentities(result1.Principal.Identities);
  }

  var result2 = await context.AuthenticateAsync("MyScheme2");
  if (result2?.Principal != null)
  {
      principal.AddIdentities(result2.Principal.Identities);
  }

  context.User = principal;

  await next();
});

当然,您也可以将认证逻辑从三个方案移到一个方案中。

于 2020-03-23T05:49:16.387 回答