Don*_*tty 6 c# authentication jwt azure-ad-b2c asp.net-core
请参阅下面的更新
我正在使用 Azure AD B2C,希望我的用户能够通过我的 Web 应用程序登录,并能够利用 JWT 不记名令牌并从移动应用程序调用 Web API 方法。
我可以让任一身份验证方案自行工作。例如,在我的startup.cs中我可以执行以下操作:
services
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));
Run Code Online (Sandbox Code Playgroud)
其按预期工作(用户可以登录网站,但 JWT 不起作用)。
或者,我可以使用以下内容,然后只有 JWT 不记名令牌才可以工作:
services
.AddAuthentication(AzureADB2CDefaults.JwtBearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
Run Code Online (Sandbox Code Playgroud)
如果我想要其中任何一个工作,我可以执行以下操作(在/sf/answers/3479447331/的帮助下)
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();
}
Run Code Online (Sandbox Code Playgroud)
现在两者都可以工作。(编辑:实际上,它们并不能完全工作)
但是,我也有这个代码:
app.UseAuthentication();
app.UseMiddleware<MyAfterAuthenticatedMiddleware>();
app.UseAuthorization();
Run Code Online (Sandbox Code Playgroud)
问题是,当我使用任一身份验证的组合时,当我的中间件代码运行时,我的用户未经过身份验证(在中间件代码中)并且没有声明等,但稍后在管道中获取它们。
这里发生了什么事?如何解决这个问题?
看来,当我不指定默认身份验证方案时(为了拥有多个方案),直到管道中的授权步骤时,身份验证才会发生。
我需要我的中间件在身份验证之后和授权之前运行。如何通过多种身份验证方案实现这一点?
更新——解决了!但一定有更好的方法!
首先,我要向那些创建 .NET 安全产品的人们表示敬意。这很重要,也很困难。但我确实认为可能还有很大的改进空间。
大多数开发人员在必要时都会涉足安全领域,然后又回到他们的“常规”工作中。除非你每天都使用它,否则很难保持领先。每次你回到它时,一切都会再次改变。
这一定是一个常见的场景:我希望我的用户能够登录我的网站并与各种 Web API 方法进行交互。我希望他们也能够通过其他方式访问这些相同的 API 方法,例如移动应用程序 - 我将在其中使用 JWT 令牌或等效方法。
这应该不难做。
然而,我却陷入了为此创建处理程序和政策的困境中。一件事会起作用,但另一件事不会。然后,当我认为事情是正确的时,我发现一些挑战和禁止逻辑并没有按预期工作。
内置的授权中间件具有进行身份验证的能力——这是我早期走的路之一,结果发现它并没有完全发挥作用——并且它给我带来了其他问题,如上所述。
我认为,授权期间不应该进行身份验证。身份验证应该在预期的地方进行——在身份验证中间件中。(我的猜测是,它是在授权中添加的,以便解决多年前出现的其他一些问题 - 也许今天仍然存在)
不管怎样——这就是我最终让事情开始工作的方法。它可能会更干净、更光滑、更灵活,但它可以满足我的需求。而且它比我见过的任何其他东西都不像黑客。但是有没有一个更好的内置类可以为我完成这个任务呢?
我的新问题是:有没有比我下面描述的更好的方法来完成这项工作?。很难相信这是最好的方法。
在 Startup.ConfigureServices 中,我现在有以下内容:
services
.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
Run Code Online (Sandbox Code Playgroud)
然后我还有:
services.AddHttpContextAccessor();
services.AddSingleton<IAuthenticationSchemeProvider, MyAuthenticationSchemeProvider>();
Run Code Online (Sandbox Code Playgroud)
最后,我有一个新课程:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以使用两种身份验证、质询和禁止按预期工作。为什么没有一个允许在身份验证方案之间切换的内置类?为什么授权中间件尝试使用多个方案进行身份验证(我说它根本不应该这样做),而不是身份验证中间件?
现在,这适用于遇到类似问题的其他人。
| 归档时间: |
|
| 查看次数: |
1951 次 |
| 最近记录: |