ASP.NET Core集成测试本地通过但GitHub Actions报403 Forbidden
ASP.NET Core 8 Web API集成测试GitHub Actions 403 Forbidden问题排查
问题背景
我正在为ASP.NET Core 8 Web API项目运行集成测试,某测试在本地Visual Studio Test Explorer中可正常通过,但在GitHub Actions执行时出现403 Forbidden错误。
相关代码
GenerateToken.cs(ProSys.Tests.Integration项目)
public class GenerateToken { private readonly HttpClient _client; public GenerateToken(CustomWebApplicationFactory<Program> factory) { _client = factory.CreateClient(); } public async Task<string> GetJwtToken() { var loginPayload = new { username = "owner", password = "P@$$w0rd" }; var response = await _client.PostAsJsonAsync("/api/v1/account/login", loginPayload); response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync(); var json = JsonSerializer.Deserialize<ApiResponseWrapper<LoginResponseResult>> (responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, Converters = { new JsonStringEnumConverter() } }); if (json?.Value?.Token == null) { throw new Exception($"Token generation failed. Response: {responseContent}"); } return json.Value.Token; } }
AuthTests.cs
public class AuthTests : IClassFixture<CustomWebApplicationFactory<Program>> { private readonly HttpClient _client; private readonly GenerateToken _generateToken; public AuthTests(CustomWebApplicationFactory<Program> factory) { _client = factory.CreateClient(); _generateToken = new GenerateToken(factory); } [Fact] public async Task Get_Protected_Endpoint_Should_Return_Unauthorized_Without_Token() { var response = await _client.GetAsync("/api/v1/userType/retrieve"); response.StatusCode.Should().Be(System.Net.HttpStatusCode.Unauthorized); } [Fact] public async Task Get_Protected_Endpoint_Should_Return_Success_With_Dynamic_Token() { var token = await _generateToken.GetJwtToken(); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await _client.GetAsync("/api/v1/userType/retrieve"); response.EnsureSuccessStatusCode(); } }
问题详情
测试流程如下:
- 使用有效凭据(owner / P@$$w0rd)调用
/api/v1/account/login端点获取JWT令牌 - 将令牌放入Authorization头,调用受保护的
/api/v1/userType/retrieve端点 - 本地测试返回200 OK符合预期,但GitHub Actions中返回403 Forbidden
已确认GitHub Actions中数据库表创建和数据插入正常,owner用户凭据正确且拥有该端点访问权限(Postman携带令牌调用正常)。令牌采用RSA算法签发验证,公私钥存储在GitHub Secrets的secrets.json中,API登录流程可正常使用该密钥处理JWT。
GitHub Actions错误信息
ProSys.Tests.Integration.Tests.AuthTests.AuthTests.Get_Protected_Endpoint_Should_Return_Success_With_Dynamic_Token [FAIL] [xUnit.net 00:00:12.08] System.Net.Http.HttpRequestException : Response status code does not indicate success: 403 (Forbidden).
疑问
- 如何调试GitHub Actions中是否正确读取到
secrets.json? - 排查本地可用但GitHub Actions中令牌被拒绝(403 Forbidden)的最佳方法有哪些?
解答
1. 验证GitHub Actions是否读取到secrets.json
- 在GitHub Actions workflow中添加临时步骤,将secrets内容输出到日志(调试完成后立即移除,避免密钥泄露):
- name: Debug secrets.json content run: echo "${{ secrets.YOUR_SECRETS_JSON_KEY }}" shell: bash - 在测试代码的配置加载逻辑中添加临时日志,打印RSA密钥片段(比如前20个字符),确认是否正确加载:
// 在CustomWebApplicationFactory或Program.cs配置中添加 var rsaPublicKey = Configuration["Jwt:PublicKey"]; Console.WriteLine($"Loaded RSA Public Key (partial): {rsaPublicKey?.Substring(0, 20)}..."); - 检查workflow中是否将secrets.json写入到项目的正确路径,示例:
- name: Create secrets.json run: echo "${{ secrets.SECRETS_JSON }}" > ./ProSys.Api/appsettings.secrets.json shell: bash
2. 排查令牌在GitHub Actions中被拒绝的方法
- 打印并验证令牌内容:在
GenerateToken.cs的GetJwtToken方法中临时打印生成的令牌,拿到后用JWT解析工具检查声明(claims)是否与本地一致,重点确认权限相关的claim(如role、permissions):// 在GenerateToken.cs中添加临时日志 Console.WriteLine($"Generated Token: {json.Value.Token}"); - 检查令牌验证逻辑一致性:确认GitHub Actions环境中,API的JWT验证配置与本地一致:
- 验证算法是否为RS256,公钥是否正确加载
- 检查令牌过期时间(
expclaim),是否因环境时区差异导致令牌提前过期
- 输出授权上下文日志:在受保护端点的授权过滤器或方法中添加日志,打印当前用户的身份信息和权限,确认与本地测试时一致:
// 在授权逻辑中添加 var user = HttpContext.User; Console.WriteLine($"Authenticated User: {user.Identity.Name}, Roles: {string.Join(",", user.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value))}"); - 配置转发头:若API在GitHub Actions中使用HTTPS,确保正确配置转发头,避免请求上下文异常导致验证失败:
// 在Program.cs中添加 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); - 对比环境变量:在workflow中打印所有相关环境变量,确认与本地开发环境配置一致:
- name: Print environment variables run: printenv | grep -E "JWT|ASPNETCORE" shell: bash
内容的提问来源于stack exchange,提问作者Hadi Soufan
相关产品推荐
相关产品推荐

