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

.NET 8 ASP.NET Core MVC授权认证集成测试HttpClient配置问题

问题

我在MVC应用中通过外部服务完成认证,回调获取JWT Token后,按以下代码创建认证Cookie:

public class AuthorizationController(IConfiguration configuration) : Controller
{
    public async Task<IActionResult> CallBack(string atoken)
    {
        var key = configuration["JWT:Secret"];
        var tokenHandler = new JwtSecurityTokenHandler();
        var res = tokenHandler.ValidateToken(atoken, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey =
                new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(key)),
            ValidateIssuer = false,
            ValidateAudience = false
        }, out _);
        var identity = new ClaimsIdentity(res.Claims, CookieAuthenticationDefaults.AuthenticationScheme);

        await HttpContext.SignOutAsync();
        await HttpContext.SignInAsync(new ClaimsPrincipal(identity),
            new AuthenticationProperties
            {
                IsPersistent = true,
                ExpiresUtc = DateTimeOffset.MaxValue,
                AllowRefresh = true
            });
        return RedirectToAction("Index", "PagesView");
    }
}

授权配置如下:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.LoginPath = "/Authorization/Login";
    options.AccessDeniedPath = "/Account/AccessDenied";
});

现在编写集成测试时,遇到了授权问题:

[Test]
public async Task PostNewPage_Test()
{
    await AddRoleAuthorization(ApplicationClaimValues.SuperAdministrator);
    var command = new CreateContentCommand
    {
        PageName = _page.Name,
        Title = "title",
        Lang = "ru",
        HtmlContent = "fasdfasdf"
    };
    var response = await _httpClient.PostAsFormAsync(CreateContentUrl, command);
    Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}

我的AddRoleAuthorization方法实现如下:

protected async Task AddRoleAuthorization(string role)
{
    using var scope = _factory.Services.GetService<IServiceScopeFactory>()!.CreateScope();
    var token = _tokenService.CreateTokenByClaims(_jwtSecret,
    [
        new Claim(ClaimTypes.Role, role),
    ]);
    var response = await _httpClient.GetAsync($"/Authorization/callback?token={token}");
    foreach (var item in response.Headers)
    {
        _httpClient.DefaultRequestHeaders.Add(item.Key, item.Value);
    }
}

问题是:发送POST请求前HttpClient已经携带Cookie,但请求仍被重定向到AuthorizationController,说明客户端未授权。请问如何正确配置HttpClient?

解决方案

你的问题主要出在Cookie管理方式错误,以及回调请求的参数不匹配,以下是具体修复步骤:

1. 用CookieContainer自动管理Cookie

HttpClient默认不会自动保存和发送Cookie,需要通过HttpClientHandler配置Cookie容器:

// 如果是直接创建HttpClient
var handler = new HttpClientHandler
{
    CookieContainer = new CookieContainer(),
    UseCookies = true
};
_httpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost:5000") };

// 如果用WebApplicationFactory,可在ConfigureWebHost中配置
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
    builder.ConfigureServices(services =>
    {
        services.AddHttpClient("TestClient")
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
            {
                CookieContainer = new CookieContainer(),
                UseCookies = true
            });
    });
}

2. 修正AddRoleAuthorization方法

  • 回调方法的参数是atoken,但测试里传的是token,这会导致控制器无法接收Token,根本不会生成认证Cookie,必须修正URL参数名
  • 不需要手动提取Headers添加到HttpClient,Cookie容器会自动保存回调请求返回的Cookie

调整后的方法:

protected async Task AddRoleAuthorization(string role)
{
    using var scope = _factory.Services.GetService<IServiceScopeFactory>()!.CreateScope();
    var token = _tokenService.CreateTokenByClaims(_jwtSecret,
    [
        new Claim(ClaimTypes.Role, role),
    ]);
    // 修正参数名为atoken,匹配控制器的参数
    var response = await _httpClient.GetAsync($"/Authorization/callback?atoken={token}");
    // 确保回调请求成功,避免后续使用无效Cookie
    response.EnsureSuccessStatusCode();
}

3. 额外验证点

  • 确认_tokenService.CreateTokenByClaims生成的JWT签名密钥和应用配置的JWT:Secret完全一致
  • 检查测试目标接口是否正确添加了[Authorize]或[Authorize(Roles = ...)]特性
  • 可添加调试代码查看Cookie容器中的内容,确认认证Cookie已被保存:
var cookies = ((HttpClientHandler)_httpClient.MessageHandler).CookieContainer.GetCookies(new Uri("http://localhost:5000"));
foreach (Cookie cookie in cookies)
{
    Console.WriteLine($"{cookie.Name}: {cookie.Value}");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:04:53