.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
相关产品推荐
相关产品推荐

