我在ASP.NET核心API项目中遇到了一个奇怪的情况.我正在试着通过IActionContextAccessor
IS AuthenticationHandler
进入ActionContext
.现在我发现,当我只有1AuthenticationScheme
个注册时,返回的ActionContext
是null
,但是一旦我添加第二个AuthenticationScheme
,ActionContext
就正确地返回了.
下面的代码是最小化的再现场景.我有一个设置身份验证方案的程序.cs.当我在项目中调用一个随机的API路径,并且在HandleAuthenticateAsync
方法中有一个断点时,我看到ActionContext
被填满了.然而,一旦我注释掉注册Schema2
身份验证处理程序的行,ActionContext
就变成空的.当命中同一断点时.
有人能解释一下这里发生了什么吗?
我的程序.cs:
using AuthHandlerTest;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Infrastructure;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
builder.Services.AddControllers(options =>
{
options.Filters.Add(new AuthorizeFilter());
});
builder.Services.AddAuthentication()
.AddScheme<Schema1Options, Schema1>("schema1", null);
.AddScheme<Schema2Options, Schema2>("schema2", null);
builder.Services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder("schema1").RequireAuthenticatedUser().Build();
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthentication();
app.UseRouting();
app.MapControllers();
app.Run();
我的架构1.cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Text.Encodings.Web;
namespace AuthHandlerTest;
public class Schema1Options : AuthenticationSchemeOptions
{
}
public class Schema1 : AuthenticationHandler<Schema1Options>
{
private readonly IActionContextAccessor _actionContextAccessor;
public Schema1(IOptionsMonitor<Schema1Options> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IActionContextAccessor actionContextAccessor) : base(options, logger, encoder, clock)
{
_actionContextAccessor = actionContextAccessor;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
//this variable is null when only having 1 scheme registered
var actionContext = _actionContextAccessor.ActionContext;
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "aa"),
};
var claimsIdentity = new ClaimsIdentity(claims, "schema1");
var ticket = new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity), "schema1");
return Task.FromResult(AuthenticateResult.Success(ticket));
}
}
架构2.cs与架构1.cs相同,只是1‘S被替换为2’S.
我还看到,在工作和非工作场景中,堆栈跟踪有很大的不同.
现在我理解了为什么这些不同的堆栈导致ActionContext
可用或不可用,因为在工作情况下,ResourceInvoker
存在于调用堆栈中,并且该组件确保IActionContextAccessor
获得ActionContext
属性.重要的问题是,是什么导致了调用堆栈的差异
最新情况: 我添加了一个完整的重现场景here