ASP.NET Core 7 Web Api集成IdentityServer与Google OAuth时state无效
问题根源及修复方案
1. 认证Scheme与中间件顺序错误
这是触发oauth state was missing or invalid的核心原因:
- Google OAuth的SignInScheme配置错误:你将
googleOptions.SignInScheme设为IdentityServerJwtConstants.IdentityServerJwtBearerScheme,但该Scheme用于JWT Bearer认证,OAuth2流程需要用Cookie Scheme存储state参数(防止CSRF攻击),正确值应为IdentityConstants.ExternalScheme(外部登录专用Cookie Scheme)。 - 中间件顺序冗余且错误:
UseIdentityServer已包含认证逻辑处理,无需额外调用UseAuthentication,且UseAuthorization必须在UseIdentityServer之后执行。
修正后的服务配置代码
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) { // 数据库上下文配置保持不变 if (configuration.GetValue<bool>("UseInMemoryDatabase")) { services.AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase("DreamBookDb")); } else { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), builder => builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); } services.AddScoped<IApplicationDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>()); services.AddScoped<ApplicationDbContextInitialiser>(); services .AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(); // 调整认证配置:使用外部Cookie Scheme处理Google登录 services.AddAuthentication() .AddIdentityServerJwt() .AddGoogle(googleOptions => { googleOptions.ClientId = configuration["Authentication:Google:ClientId"]; googleOptions.ClientSecret = configuration["Authentication:Google:ClientSecret"]; googleOptions.SignInScheme = IdentityConstants.ExternalScheme; }); return services; }
2. Swagger配置错误:直接对接Google而非IdentityServer
当前Swagger直接请求Google授权端点,但在IdentityServer架构中,需让Swagger对接IdentityServer的授权端点,由IdentityServer统一处理外部登录流程,确保state参数被正确管理。
修正后的Swagger服务配置代码
static void AddSwaggerServices(IServiceCollection services, IConfiguration configuration) { services.AddSwaggerGen(setup => { setup.SwaggerDoc("v1", new OpenApiInfo { Title = "DreamBook", Version = "v1" }); // 配置OAuth2对接IdentityServer setup.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows() { AuthorizationCode = new OpenApiOAuthFlow() { AuthorizationUrl = new Uri("https://localhost:44385/connect/authorize"), TokenUrl = new Uri("https://localhost:44385/connect/token"), Scopes = new Dictionary<string, string> { { "DreamBookAPI", "DreamBook API 访问权限" } } } } }); setup.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "oauth2", Type = ReferenceType.SecurityScheme } }, new List<string> { "DreamBookAPI" } } }); }); }
修正后的SwaggerUI配置代码
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "DreamBook v1"); c.OAuthClientId("DreamBookAPI_Swagger"); c.OAuthAppName("DreamBook API Swagger"); c.OAuthUsePkce(); });
3. 请求管道顺序修正
移除冗余的UseAuthentication调用,确保中间件执行顺序符合IdentityServer要求:
var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "DreamBook v1"); c.OAuthClientId("DreamBookAPI_Swagger"); c.OAuthAppName("DreamBook API Swagger"); c.OAuthUsePkce(); }); // 数据库初始化代码保持不变 using (var scope = app.Services.CreateScope()) { var initialiser = scope.ServiceProvider.GetRequiredService<ApplicationDbContextInitialiser>(); await initialiser.InitialiseAsync(); await initialiser.SeedAsync(); } } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseIdentityServer(); app.UseAuthorization(); app.MapControllers(); app.Run();
4. 补充IdentityServer客户端配置
需在ApplicationDbContextInitialiser的SeedAsync方法中添加Swagger客户端配置,确保IdentityServer认可Swagger为合法客户端:
public async Task SeedAsync() { // 其他种子数据保持不变 var swaggerClient = new Client { ClientId = "DreamBookAPI_Swagger", ClientName = "DreamBook API Swagger", AllowedGrantTypes = GrantTypes.Code, RequirePkce = true, RequireClientSecret = false, RedirectUris = { "https://localhost:44385/swagger/oauth2-redirect.html" }, PostLogoutRedirectUris = { "https://localhost:44385/swagger/" }, AllowedScopes = { "openid", "profile", "DreamBookAPI" } }; using var context = new ApplicationDbContext(_options); if (!context.Clients.Any(c => c.ClientId == swaggerClient.ClientId)) { context.Clients.Add(swaggerClient); await context.SaveChangesAsync(); } }
5. 验证Google开发者控制台配置
确保Google开发者控制台中配置的授权回调地址包含https://localhost:44385/signin-google,该地址是Google回调到你的应用的默认路径,必须与控制台配置完全一致。
内容的提问来源于stack exchange,提问作者Dilshod K
相关产品推荐
相关产品推荐

