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

.NET Core 3.1集成Keycloak OIDC实现SSO登录报错排查

问题描述

我有一个基于.NET Core 3.1开发的旧应用,计划通过Keycloak结合OpenID Connect(OIDC)实现单点登录(SSO)。当前启动应用后可以正常跳转到Keycloak登录页面,但登录成功返回应用页面时出现错误。

现有配置信息

Startup.cs

services.AddAuthorization(options =>
{
    options.AddPolicy("Admin", policy => policy.RequireClaim("user_roles", "admin"));
    options.AddPolicy("Contractor", policy => policy.RequireClaim("user_roles", "contractor"));
    options.AddPolicy("Users", policy => policy.RequireClaim("user_roles", "users"));
    options.AddPolicy(
        "Admin",
        policyBuilder => policyBuilder.RequireAssertion(
            context => context.User.HasClaim(claim =>
                       claim.Type == "admin" && (claim.Value == "contractor" || claim.Value == "users")
        ))
    );
});

services.AddAuthentication(options =>
{
    // We check the cookie to confirm that we are authenticated
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    // When we sign in we will deal out a cookie
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    //Use this to check if we are alllowed to do something.
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddOpenIdConnect(options =>
{
options.CallbackPath = "/Index";
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.Authority = Configuration["Authentication:oidc:Authority"];
    options.ClientId = Configuration["Authentication:oidc:ClientId"];
    //options.ResponseType = useLoadTest ? "code id_token token" : "code id_token";
    options.RequireHttpsMetadata = false;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = false;
    options.RemoteSignOutPath = "/protocol/openid-connect/logout";
    options.SignedOutRedirectUri = "Redirect-here";
    //options.SignedOutRedirectUri = callBackUrl.ToString();
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
})
.AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(60));

appsettings.json

"Authentication": {
    "oidc": {
      "Authority": "http:/keycloak-testing-ip/auth/realms/project",
      "ClientId": "demo"
    }
}

登录前页面:
登录前页面

登录后页面:
登录后页面

请问我遗漏了哪些配置或步骤?


解决方案

你的配置存在多个关键问题,以下是具体修正点:

1. 重复定义授权策略导致冲突

你两次添加了名为Admin的授权策略,第二次定义会覆盖第一次,直接导致权限判断逻辑混乱。删除其中不符合需求的策略,比如保留最初的角色判断策略:

services.AddAuthorization(options =>
{
    options.AddPolicy("Admin", policy => policy.RequireClaim("user_roles", "admin"));
    options.AddPolicy("Contractor", policy => policy.RequireClaim("user_roles", "contractor"));
    options.AddPolicy("Users", policy => policy.RequireClaim("user_roles", "users"));
    // 删除重复的Admin策略定义
});

2. 错误设置OIDC回调路径

CallbackPath被设置为/Index(业务页面路径),但OIDC回调需要专门路径处理Keycloak返回的授权码,不能直接指向业务页面。建议使用默认的/signin-oidc(框架会自动处理),或者设置专门的回调路径:

.AddOpenIdConnect(options =>
{
    // 移除错误的CallbackPath配置,使用默认值
    // options.CallbackPath = "/Index";
    // ... 其他配置
})

3. Authority URL格式错误

appsettings.json中的Authority少了一个斜杠,http:/应为http://,这会导致应用无法正确获取Keycloak的OIDC元数据:

"Authentication": {
    "oidc": {
      "Authority": "http://keycloak-testing-ip/auth/realms/project",
      "ClientId": "demo"
    }
}

4. 无效的登出重定向URL

SignedOutRedirectUri设置为"Redirect-here"是无效值,需要指定具体的应用内URL,比如首页:

.AddOpenIdConnect(options =>
{
    options.SignedOutRedirectUri = "/";
    // ... 其他配置
})

5. 未配置Keycloak角色映射

Keycloak的角色默认存储在realm_access.roles嵌套JSON字段中,.NET Core不会自动提取这些角色作为Claim。需要添加Claim转换规则,将角色映射到策略中使用的user_roles类型:

.AddOpenIdConnect(options =>
{
    // ... 其他配置
    options.ClaimActions.MapJsonKey("user_roles", "realm_access.roles");
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "user_roles"
    };
})

6. 中间件配置顺序错误

确保在Configure方法中正确添加认证和授权中间件,且顺序必须在UseRouting之后、UseEndpoints之前:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ... 其他中间件(如UseStaticFiles、UseDeveloperExceptionPage等)
    
    app.UseRouting();

    // 必须先添加认证中间件,再添加授权中间件
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

7. 错误设置远程登出路径

RemoteSignOutPath被设置为/protocol/openid-connect/logout(Keycloak自身的登出端点),应用的远程登出回调路径应使用默认的/signout-callback-oidc,或与Keycloak客户端配置的"Valid Redirect URIs"和"Backchannel Logout URL"保持一致:

.AddOpenIdConnect(options =>
{
    // 使用默认的远程登出回调路径
    // options.RemoteSignOutPath = "/protocol/openid-connect/logout";
    // ... 其他配置
})

完成以上修正后,重新启动应用即可正常完成SSO流程。

内容的提问来源于stack exchange,提问作者akayh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 23:47:31