.NET 7 API添加[Authorize]后出现No authenticationScheme指定错误求助
问题原因
你在.NET7中同时存在Program.cs和Startup.cs,但.NET7默认采用顶级语句的启动模式,没有自动加载Startup.cs中的配置。你的JWT认证逻辑写在Startup.cs的ConfigureServices里,但这些代码根本没被执行,导致应用服务容器中缺少认证方案的配置,触发了"No authenticationScheme was specified..."错误。
解决方案
你可以选择以下两种方式修复:
方式一:将Startup配置合并到Program.cs
直接把Startup.cs中的服务配置和中间件逻辑迁移到Program.cs,这是.NET7推荐的写法:
修改后的Program.cs完整代码:
using System.Text; using System.Globalization; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Hangfire; using Hangfire.SqlServer; var builder = WebApplication.CreateBuilder(args); // 从Startup迁移的服务配置 builder.Services.AddResponseCompression(); builder.Services.AddCors(); builder.Services.AddControllers(); // 添加DbContext builder.Services.AddDbContext<VisionContexto>( opt => opt.UseSqlServer(builder.Configuration.GetConnectionString("VisionContexto"), b => b.MigrationsAssembly("Vision.Dados"))); // JWT认证配置 var key = Encoding.ASCII.GetBytes(builder.Configuration.GetValue<string>("Configuracoes:ChaveSecreta")); builder.Services.AddAuthentication(x => { x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.IncludeErrorDetails = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateLifetime = true, ValidateIssuer = false, ValidateAudience = false, ClockSkew = TimeSpan.Zero }; }); // API版本控制 builder.Services.AddApiVersioning(options => { options.ReportApiVersions = true; options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = ApiVersion.Default; options.ApiVersionReader = ApiVersionReader.Combine(new MediaTypeApiVersionReader("x-api-version"), new HeaderApiVersionReader("x-api-version")); }); builder.Services.AddVersionedApiExplorer(options => { options.GroupNameFormat = "'v'VV"; options.SubstituteApiVersionInUrl = true; }); // Swagger配置 builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.OperationFilter<SwaggerDefaultValues>(); c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "Vision API", Version = "v1", Description = "Vision Web API", Contact = new Microsoft.OpenApi.Models.OpenApiContact { Name = "Vision", Email = "app@prodadosinformatica.com.br", Url = new Uri("https://www.prodadosinformatica.com.br") } }); c.DocInclusionPredicate((_, api) => !string.IsNullOrWhiteSpace(api.GroupName)); c.TagActionsBy(api => api.GroupName); string caminhoAplicacao = AppContext.BaseDirectory; string nomeAplicacao = System.Reflection.Assembly.GetEntryAssembly().GetName().Name; string caminhoXmlDoc = Path.Combine(caminhoAplicacao, $"{nomeAplicacao}.xml"); c.IncludeXmlComments(caminhoXmlDoc); }); builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerGenOptions>(); // Hangfire配置 builder.Services.AddHangfire(configuration => configuration .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() .UseSqlServerStorage(builder.Configuration.GetConnectionString("VisionContexto"), new SqlServerStorageOptions { CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), QueuePollInterval = TimeSpan.Zero, UseRecommendedIsolationLevel = true, DisableGlobalLocks = true })); builder.Services.AddHangfireServer(); // 其他配置 builder.Services.Configure<PasswordHasherOptions>(options => options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2); builder.Services.AddOptions(); builder.Services.Configure<Configuracoes.Configuracoes>(builder.Configuration.GetSection("Configuracoes")); // 本地化配置 builder.Services.Configure<RequestLocalizationOptions>( options => { var supportedCultures = new List<CultureInfo> { new CultureInfo("pt-BR"), }; options.DefaultRequestCulture = new RequestCulture(culture: "pt-BR", uiCulture: "pt-BR"); options.SupportedCultures = supportedCultures; options.SupportedUICultures = supportedCultures; }); Thread.CurrentThread.CurrentCulture = new CultureInfo("pt-BR"); Thread.CurrentThread.CurrentUICulture = new CultureInfo("pt-BR"); // 日志配置 builder.Logging.AddDbLogger(options => { builder.Configuration.GetSection("Logging") .GetSection("Log").GetSection("Options").Bind(options); }); var app = builder.Build(); // 中间件配置(从Startup迁移) if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(options => { var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>(); foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); } options.RoutePrefix = string.Empty; }); app.UseResponseCompression(); app.UseHttpsRedirection(); app.UseRouting(); app.UseCors(x => x .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
方式二:在Program.cs中显式使用Startup类
如果你想保留Startup.cs,只需在Program.cs中添加一行代码,让应用加载Startup的配置:
修改后的Program.cs:
var builder = WebApplication.CreateBuilder(args); // 显式指定使用Startup类 builder.WebHost.UseStartup<Startup>(); var app = builder.Build(); app.Run();
注意:这种方式下,
Program.cs中原来的服务配置和中间件代码需要删除,避免和Startup.cs中的配置重复冲突。
关键注意点
- 中间件顺序必须正确:
UseCors要放在UseAuthentication和UseAuthorization之前,否则CORS配置不会生效。 - 确保
appsettings.json中存在Configuracoes:ChaveSecreta配置项,且值是有效的密钥字符串。
内容的提问来源于stack exchange,提问作者Saulo Pacífico
相关产品推荐
相关产品推荐

