【发布时间】:2019-04-10 11:52:46
【问题描述】:
我们正在尝试了解在注册了多个身份验证方案时对 ChallengeResult 的预期处理方式。
我们需要处理这种情况,因为我们有一个 ASP.NET core 2.2 应用程序公开了一些操作方法(我们使用 MVC 中间件),这些操作方法必须由依赖于 cookie 身份验证的 angularjs SPA 和一些第三方应用程序使用使用基于 Authorization HTTP 请求标头的身份验证机制。请注意两个用户所涉及的操作方法是相同的,这意味着每个用户都必须允许使用 cookie 和基于 Authorization HTTP 请求标头的自定义方案进行身份验证。我们知道这可能不是最佳设计,但我们无法修改整体架构。
This documentation 似乎证实了我们想要实现的目标完全可以使用 ASP.NET core 2.2 实现。不幸的是,UI 应用程序使用的 cookie 身份验证和第三方使用的自定义身份验证必须在身份验证挑战的情况下表现不同,并且它们的预期行为彼此不兼容:UI 应用程序应该将用户重定向到登录表单,而第三方应用程序需要原始 401 状态代码响应。上面链接的文档没有提供对 ChallengeResult 处理的清晰解释,因此我们决定尝试一个测试应用程序。
我们创建了两个假身份验证处理程序:
public class FooAuthenticationHandler : IAuthenticationHandler
{
private HttpContext _context;
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.Fail("Foo failed"));
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
_context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.CompletedTask;
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
_context = context;
return Task.CompletedTask;
}
}
public class BarAuthenticationHandler : IAuthenticationHandler
{
private HttpContext _context;
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.Fail("Bar failed"));
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
_context.Response.StatusCode = StatusCodes.Status500InternalServerError;
return Task.CompletedTask;
}
public Task ForbidAsync(AuthenticationProperties properties)
{
return Task.CompletedTask;
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
_context = context;
return Task.CompletedTask;
}
}
我们在 ConfigureServices 方法中注册了身份验证模式,如下所示:
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "Bar";
options.AddScheme<FooAuthenticationHandler>("Foo", "Foo scheme");
options.AddScheme<BarAuthenticationHandler>("Bar", "Bar scheme");
});
}
这是我们的中间件管道:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
最后我们创建了一个控制器,其中包含需要身份验证的操作方法:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values/5
[HttpGet("{id}")]
[Authorize(AuthenticationSchemes = "Foo,Bar")]
public ActionResult<string> Get(int id)
{
return "value";
}
}
我们注意到:
-
FooAuthenticationHandler和BarAuthenticationHandler都被调用来处理 ChallengeResult - 顺序是
FooAuthenticationHandler在BarAuthenticationHandler之前,取决于Authorize属性(如果您交换Authorize属性内的身份验证方案,则首先调用BarAuthenticationHandler) - 调用者得到一个原始的 500 状态码响应,但这仅取决于调用授权处理程序的顺序
- 对
options.DefaultChallengeScheme = "Bar";的调用很重要当且仅当 在[Authorize]属性内属性AuthenticationSchemes设置为未。如果这样做,则只会调用BarAuthenticationHandler,而FooAuthenticationHandler永远不会有机会对请求进行身份验证或处理身份验证质询。
所以,问题基本上是:当您遇到这种情况时,您希望如何处理不同身份验证方案在 ChallengeResult 处理方面可能出现的“不兼容”,因为它们被 both 调用?
我们认为双方都有机会对请求进行身份验证很好,但我们想知道是否有可能决定由哪一个来处理身份验证挑战。
感谢您的帮助!
【问题讨论】:
标签: c# authentication asp.net-core .net-core authorization