ASP.NET Core 8 Web API与Blazor WASM部署后周期性CORS错误求助
我用.NET 8搭建了ASP.NET Core 8 Web API与Blazor WASM应用,采用JWT认证。API中的CORS初始配置如下:
builder.Services.AddCors(options => { options.AddDefaultPolicy(policy =>{policy.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials();}); }); ... var app = builder.Build(); ... app.UseCors();
问题现象
部署后一切正常,但约一周后开始出现CORS错误:
Access to fetch at 'https://backend.net/api/packages/fullpackage' from origin 'https://frontend.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
查看预检请求返回信息:
access-control-allow-credentials: true access-control-allow-headers: authorization,content-type access-control-allow-methods: POST
实际请求返回:
URL: https://backend.net/api/packages/fullpackage Method: POST Code: 500 Internal Server Error Directive: strict-origin-when-cross-origin
该问题周期性出现,更换API主机后曾恢复正常,但一周后再次复发。
已尝试的解决方案
- 指定前端URL配置CORS
- 重启应用程序池(application pool)
- 清理应用程序池
- 清除缓存
- 添加自定义策略并在控制器中使用
[EnableCors(PolicyName="name")]启用 - 在控制器中使用
[DisableCors]禁用CORS
最初有效的CORS配置为:
app.UseCors(x => x .AllowAnyMethod() .AllowAnyHeader() .SetIsOriginAllowed(origin => true) .AllowCredentials());
之后切换为初始的builder方式配置后失效,直到更换主机才恢复。
完整API代码
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using System.Text; using System.Text.Json.Serialization; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers().AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "TSystem API", Version = "v1" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = @"JWT Authorization header using the Bearer scheme. <br /> <br /> Enter 'Bearer' [space] and then your token in the text input below.<br /> <br /> Example: 'Bearer 12345abcdef'<br /> <br />", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = "Bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header, }, new List<string>() } }); }); Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("MYLIC"); var isDev = builder.Environment.IsDevelopment; if (isDev.Invoke()) { //LocalConnection builder.Services.AddDbContext<DataContext>(x => x.UseSqlServer("name=LocalConnection")); } else { //CloudConnection builder.Services.AddDbContext<DataContext>(x => x.UseSqlServer("name=CloudConnection")); } builder.Services.AddTransient<SeedDb>(); builder.Services.AddScoped<IApiService, ApiService>(); builder.Services.AddScoped<IFileStorage, FileStorage>(); builder.Services.AddScoped<IMailHelper, MailHelper>(); builder.Services.AddIdentity<User, IdentityRole>(x => { x.Tokens.AuthenticatorTokenProvider = TokenOptions.DefaultAuthenticatorProvider; x.SignIn.RequireConfirmedEmail = true; x.User.RequireUniqueEmail = true; x.Password.RequireDigit = false; x.Password.RequiredUniqueChars = 0; x.Password.RequireLowercase = false; x.Password.RequireNonAlphanumeric = false; x.Password.RequireUppercase = false; x.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); x.Lockout.MaxFailedAccessAttempts = 3; x.Lockout.AllowedForNewUsers = true; }) .AddEntityFrameworkStores<DataContext>() .AddDefaultTokenProviders(); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(x => x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["jwtKey"]!)), ClockSkew = TimeSpan.Zero }); builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials(); }); }); //This tried calling it from the controller builder.Services.AddCors(options => { options.AddPolicy(name: "DefaultCorsPolicy", policy => { policy.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials(); }); }); var app = builder.Build(); SeedData(app); void SeedData(WebApplication app) { IServiceScopeFactory? scopedFactory = app.Services.GetService<IServiceScopeFactory>(); using (IServiceScope? scope = scopedFactory!.CreateScope()) { SeedDb? service = scope.ServiceProvider.GetService<SeedDb>(); service!.SeedAsync().Wait(); } } app.UseCors(); //app.UseCors(x => x //.AllowAnyMethod() //.AllowAnyHeader() //.SetIsOriginAllowed(origin => true) //.AllowCredentials()); //app.UseCors(x => x // .AllowAnyMethod() // .AllowAnyHeader() // .WithOrigins("https://frontend.com") //changed the original name // .AllowCredentials()); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
请问我是否遗漏了什么配置或排查点?
内容的提问来源于stack exchange,提问作者menendeze

