请参阅下面的更新
我正在使用Azure AD B2C,希望用户能够通过我的Web应用程序登录,并能够利用JWT承载令牌并从移动应用程序调用Web API方法。
我可以使任一种身份验证方案都能自行工作。例如,在我的startup.cs中,我可以执行以下操作:
services
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));
可以正常工作(用户可以登录网站,但是JWT不起作用)。
或者,我可以改用以下代码,然后只有JWT承载令牌才能工作:
services
.AddAuthentication(AzureADB2CDefaults.JwtBearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
如果我要工作,可以执行以下操作(在https://stackoverflow.com/a/49706390的帮助下)
services
.AddAuthentication()
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(AzureADB2CDefaults.AuthenticationScheme, AzureADB2CDefaults.JwtBearerAuthenticationScheme)
.Build();
}
现在两者都可以工作。 (编辑:实际上,它们不能完全正常工作)
但是,我也有以下代码:
app.UseAuthentication();
app.UseMiddleware<MyAfterAuthenticatedMiddleware>();
app.UseAuthorization();
问题是,当我使用两种身份验证的组合时,当我的中间件代码运行时,我的用户未经过身份验证(在中间件代码中)并且没有声明等,但是稍后在管道中获取它们。
>这是怎么回事?以及如何解决?
似乎,当我没有指定默认的身份验证方案时-为了具有多个方案-直到管道中的授权步骤,身份验证才发生。
我需要我的中间件在身份验证之后和授权之前运行。 如何通过多种身份验证方案实现这一目标?
更新-已解决!但是必须有更好的方法!??
首先,对于那些创建.NET安全性东西的人,我要表示敬意。这很重要,也很困难。 但是我确实认为可能还有很多改进的空间。
大多数开发人员不得不在需要时涉足安全性,然后再回到他们的“常规”工作中。除非您每天都在使用它,否则很难保持领先地位。又改变了。
这必须是常见的情况:我希望我的用户能够登录到我的网站并与各种Web API方法进行交互。我希望他们也能够通过其他方式(例如移动应用程序)访问这些相同的API方法,而我将使用JWT令牌或等效方法。
这应该很容易。
但是,我将自己束之高阁,为此创建了处理程序并为此制定了策略。一件事会起作用,但另一件事却不会。然后,当我认为事情是对的时,我发现了一些挑战和禁止逻辑无法按预期工作。
内置的Authorization中间件具有进行身份验证的能力-这是我失败的早期方法之一,却发现它没有完全起作用-并给我造成了其他问题,如前所述以上。
我认为,身份验证应该不在授权过程中发生。身份验证应该在预期的地方进行-在身份验证中间件中。 (我猜想它是在授权中添加的,目的是要解决几年前出现的其他问题-也许今天仍然存在)
无论如何-这是我终于可以工作的方式。它可能更干净,更流畅,更灵活,但是可以满足我的需求。而且,它比我见过的其他任何东西都更少。但是,有没有更好的内置类可以为我做到这一点?
我的新问题是:是否有比下面所述的方法更好的方法来完成此操作?。很难相信这是最好的方法。
在Startup.ConfigureServices中,我现在具有以下内容:
services
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
然后我也有:
services.AddHttpContextAccessor();
services.AddSingleton<IAuthenticationSchemeProvider, MyAuthenticationSchemeProvider>();
最后,我有一堂新课:
public class MyAuthenticationSchemeProvider : AuthenticationSchemeProvider
{
public MyAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IHttpContextAccessor httpContextAccessor) : base(options)
{
HttpContextAccessor = httpContextAccessor;
}
protected MyAuthenticationSchemeProvider(IOptions<AuthenticationOptions> options, IDictionary<string, AuthenticationScheme> schemes, IHttpContextAccessor httpContextAccessor) : base(options, schemes)
{
HttpContextAccessor = httpContextAccessor;
}
private IHttpContextAccessor HttpContextAccessor { get; }
private bool IsBearerRequest()
{
var httpContext = HttpContextAccessor.HttpContext;
return httpContext.Request.Headers.ContainsKey("Authorization")
&& httpContext.Request.Headers["Authorization"].Any(x => x.ToLower().Contains("bearer"));
}
public async Task<AuthenticationScheme> GetMySchemeAsync()
{
return IsBearerRequest()
? await GetSchemeAsync(AzureADB2CDefaults.BearerAuthenticationScheme)
: await base.GetDefaultAuthenticateSchemeAsync();
}
public override async Task<AuthenticationScheme> GetDefaultAuthenticateSchemeAsync()
{
return await GetMySchemeAsync();
}
public override Task<AuthenticationScheme> GetDefaultChallengeSchemeAsync()
{
return GetMySchemeAsync();
}
public override Task<AuthenticationScheme> GetDefaultForbidSchemeAsync()
{
return GetMySchemeAsync();
}
}
现在,我可以同时使用两种身份验证,质询和禁止工作。为什么没有内置的类可以在身份验证方案之间进行切换?为什么授权中间件尝试使用多种方案进行身份验证(我说它根本不应该这样做),而不是身份验证中间件?
现在,这里是任何其他遇到类似问题的人。