You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,想知道哪里配置遗漏了?


问题原因分析

  1. Identity外部登录提供程序未注册:仅注册自定义认证Scheme是不够的,SignInManager.ConfigureExternalAuthenticationProperties会验证provider是否属于已注册的外部登录提供程序,未注册会导致流程中断。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:07:34