You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:40:38