ASP.NET Core Identity外部提供程序集成测试:Challenge返回401排查
.NET 9 外部登录集成测试:FakeAuthHandler返回成功但接口返回401未跳转回调
我正在为应用的外部登录提供程序编写集成测试,希望通过模拟假登录提供程序验证流程——调用/api/auth/external-login接口后,让假提供程序返回成功,并确认应用能正常跳转到回调路径。
我已在Program.cs中配置了自定义认证Scheme:
builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = FakeAuthHandler.SchemeName; options.DefaultChallengeScheme = FakeAuthHandler.SchemeName; }).AddScheme<AuthenticationSchemeOptions, FakeAuthHandler>( FakeAuthHandler.SchemeName, displayName: FakeAuthHandler.SchemeName, configureOptions: _ => { } );
FakeAuthHandler的实现代码:
public class FakeAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions> { public const string SchemeName = "TestProvider"; public FakeAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } protected override Task<AuthenticateResult> HandleAuthenticateAsync() { var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "TestExternalUser"), new Claim(ClaimTypes.Name, "Test User"), new Claim(ClaimTypes.Email, "testuser@example.com"), new Claim("urn:google:profile", "https://profiles.google.com/testuser"), }; var identity = new ClaimsIdentity(claims, SchemeName); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, SchemeName); return Task.FromResult(AuthenticateResult.Success(ticket)); } }
外部登录接口代码:
[HttpGet("/api/auth/external-login")] [AllowAnonymous] public async Task<IActionResult> ExternalLogin(string provider, string returnUrl = null) { var redirectUrl = _linkGenerator.GetPathByAction( action: nameof(AuthController.ExternalLoginCallback), controller: "Auth", values: new { returnUrl = returnUrl } ); var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); return Challenge(properties, provider); }
调试时能看到FakeAuthHandler被调用并返回成功,但/api/auth/external-login接口始终返回401,也没有跳转到回调路径。我使用的是.NET 9和Microsoft.AspNetCore.Identity 2.3.1,想知道哪里配置遗漏了?
问题原因分析
- Identity外部登录提供程序未注册:仅注册自定义认证Scheme是不够的,
SignInManager.ConfigureExternalAuthenticationProperties会验证provider是否属于已注册的外部登录提供程序,未注册会导致流程中断。 - Challenge流程处理缺失:默认的
HandleChallengeAsync方法会返回401,你的Handler未重写该方法,无法完成认证后的重定向逻辑。
解决方案
1. 将自定义Scheme注册为Identity外部登录提供程序
在Program.cs的Identity配置中添加外部登录映射:
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultUI() .AddExternalLoginProviders(providerMap => { providerMap.Add(FakeAuthHandler.SchemeName, new ExternalLoginProviderInfo( FakeAuthHandler.SchemeName, "Test Provider", typeof(FakeAuthHandler) )); });
2. 重写FakeAuthHandler的HandleChallengeAsync方法
补充认证成功后的重定向逻辑:
protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { var authResult = await HandleAuthenticateAsync(); if (authResult.Succeeded) { Context.User = authResult.Principal; var redirectUri = properties.RedirectUri; if (!string.IsNullOrEmpty(redirectUri)) { Response.Redirect(redirectUri); return; } } await base.HandleChallengeAsync(properties); }
3. 修正接口参数错误
原接口中request.ReturnUrl是无效引用,改为方法参数的returnUrl:
var redirectUrl = _linkGenerator.GetPathByAction( action: nameof(AuthController.ExternalLoginCallback), controller: "Auth", values: new { returnUrl = returnUrl } );
测试验证
完成修改后,调用/api/auth/external-login?provider=TestProvider,FakeAuthHandler会完成认证并自动跳转到ExternalLoginCallback接口,可在回调中验证用户Claims的正确性。
内容的提问来源于stack exchange,提问作者Piotrek
相关产品推荐
相关产品推荐

