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

如何在测试类中重写Program.cs禁用ASP.NET Core Razor Pages的身份验证与授权?

问题描述

我的集成测试类执行失败,报错:

System.Net.Http.HttpRequestException : Response status code does not indicate success: 302 (Found).

手动注释掉Program.cs(.NET 6)中的身份验证与授权代码后,测试就能正常运行:

//builder.Services.AddRazorPages()
//        .AddRazorPagesOptions(options => {
//            options.Conventions.AuthorizeFolder("/"); // 给所有文件夹下的页面应用[Authorize]特性
//        })
//        .AddMicrosoftIdentityUI();
builder.Services.AddRazorPages();

怎么在下面的测试类里重写Program.cs的配置,禁用ASP.NET Core Razor Pages应用的身份验证与授权?

public class IntegrationTests : IClassFixture<WebApplicationFactory<Program>> {
    private readonly WebApplicationFactory<Program> _factory;

    public IntegrationTests(WebApplicationFactory<Program> factory) {
        _factory = factory.WithWebHostBuilder(builder =>
        {
            // 为测试重写服务配置
            builder.ConfigureServices(services =>
            {
                // 移除Razor Pages的授权策略                    
                services.AddRazorPages();

            });
        });
    }

    [Theory]
    [InlineData("/")]
    public async Task Get_EndpointsReturnSecurePageAsync(string url) {
        // 准备
        var client = _factory.CreateClient();

        // 执行
        var response = await client.GetAsync(url);

        // 断言
        response.EnsureSuccessStatusCode(); // 状态码200-299
        Assert.Equal("text/html; charset=utf-8",
            response.Content.Headers.ContentType.ToString());
    }
}
解决方案

要在集成测试中禁用身份验证和授权,需要在WithWebHostBuilder的ConfigureServices里做以下操作:

  1. 清除已注册的Razor Pages相关服务,确保新配置能覆盖原有设置
  2. 重新注册不带全局授权的Razor Pages
  3. 添加一个测试用的空身份验证处理器,避免请求被重定向到登录页

修改后的测试类代码如下:

public class IntegrationTests : IClassFixture<WebApplicationFactory<Program>> {
    private readonly WebApplicationFactory<Program> _factory;

    public IntegrationTests(WebApplicationFactory<Program> factory) {
        _factory = factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                // 清除已注册的Razor Pages服务
                var razorPagesDescriptor = services.SingleOrDefault(
                    d => d.ServiceType == typeof(IRazorPagesMvcBuilder));
                if (razorPagesDescriptor != null)
                {
                    services.Remove(razorPagesDescriptor);
                }

                // 重新注册Razor Pages,清除所有全局授权约定
                services.AddRazorPages(options =>
                {
                    options.Conventions.AuthorizeFolder("/").Clear();
                });

                // 添加测试用的身份验证方案,让请求自动通过身份验证
                services.AddAuthentication("TestAuth")
                    .AddScheme<AuthenticationSchemeOptions, TestAuthenticationHandler>(
                        "TestAuth", options => { });
            });
        });
    }

    [Theory]
    [InlineData("/")]
    public async Task Get_EndpointsReturnSecurePageAsync(string url) {
        var client = _factory.CreateClient();
        var response = await client.GetAsync(url);

        response.EnsureSuccessStatusCode();
        Assert.Equal("text/html; charset=utf-8",
            response.Content.Headers.ContentType.ToString());
    }
}

// 测试用的空身份验证处理器,返回已通过验证的身份
public class TestAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public TestAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock)
        : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // 构造一个模拟的已验证身份
        var claims = new[] { new Claim(ClaimTypes.Name, "TestUser") };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return Task.FromResult(AuthenticateResult.Success(ticket));
    }
}

关键要点

  • 清除原有IRazorPagesMvcBuilder服务是为了避免原有带授权的配置生效
  • options.Conventions.AuthorizeFolder("/").Clear()直接移除了全局的文件夹授权约定
  • 测试用身份验证处理器会自动让所有请求通过身份验证,不会触发302重定向
  • 如果你的应用中间件管道里有强制的授权检查,还可以在Configure方法里调整管道,比如跳过UseAuthorization()中间件

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 00:47:47