假设我有Schema1
、Schema2
和Schema3
,则我在.NET Core API中使用add-multiple Jwt承载进行多重身份验证。
我还使用Ocelot来管理请求。在Ocelot-config中,对于每个路由,我可以声明一种并且只能声明一种身份验证类型(模式名称(。然而,在某些情况下,我需要为每条路由提供多个身份验证支持。(我需要使用Schema1
、Schema2
或Schema3
中的任一个对请求进行身份验证(。
但由于Ocelot只允许我添加一个模式名称,我必须将这3个模式合并为1个模式。
因此,基本问题是:如何定义一个通过Schema1
、Schema2
或Schema3
进行身份验证的身份验证模式(SchemaX
(?知道吗?
您可以尝试创建自定义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();
});
当然,您也可以将身份验证逻辑从三个方案移动到一个方案中。
很简单,如果有人在寻找,我会在这里回答:
基本上只需要定义一个自定义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;
}
}
}