ASP.NET集成Keycloak登录成功后IsAuthenticated始终为false
问题分析与解决方案
你遇到的User.Identity.IsAuthenticated始终为false的问题,核心原因是OpenIdConnect中间件未将Keycloak返回的认证信息写入Cookie,导致后续请求无法识别已认证身份,进而引发循环重定向。以下是具体修正方案:
关键配置缺失点
- 未关联Cookie认证类型:原OpenIdConnect配置中未指定
SignInAsAuthenticationType,导致登录后的身份信息无法持久化到Cookie中。 - 缺少令牌交换与身份生成逻辑:仅配置基础参数后,ASP.NET不会自动处理Keycloak返回的授权码,无法生成有效的
ClaimsIdentity。
修改后的完整配置代码
const string persistentAuthType = "keycloak_auth"; app.SetDefaultSignInAsAuthenticationType(persistentAuthType); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = persistentAuthType, SlidingExpiration = true, ExpireTimeSpan = TimeSpan.FromMinutes(30) // 设置Cookie过期时间 }); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { AuthenticationType = "keycloak_auth", ClientId = clientId, Authority = authorityserver, RedirectUri = "http://localhost:13636/home", PostLogoutRedirectUri = "http://localhost:13636", ClientSecret = clientSecret, RequireHttpsMetadata = false, ResponseType = OpenIdConnectResponseType.Code, Scope = "openid profile email", // 核心:指定登录后使用的Cookie认证类型 SignInAsAuthenticationType = persistentAuthType, // 配置令牌验证规则 TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = authorityserver, ValidateAudience = true, ValidAudience = clientId, ValidateLifetime = true }, // 处理授权码交换与身份生成 Notifications = new OpenIdConnectAuthenticationNotifications { AuthorizationCodeReceived = async n => { // 用授权码交换访问令牌和刷新令牌 var tokenClient = new HttpClient(); var tokenResponse = await tokenClient.PostAsync( $"{authorityserver}/protocol/openid-connect/token", new FormUrlEncodedContent(new Dictionary<string, string> { ["grant_type"] = "authorization_code", ["client_id"] = clientId, ["client_secret"] = clientSecret, ["code"] = n.Code, ["redirect_uri"] = "http://localhost:13636/home" }) ); if (!tokenResponse.IsSuccessStatusCode) throw new Exception("授权码交换令牌失败"); var tokenContent = await tokenResponse.Content.ReadAsStringAsync(); var tokens = JsonConvert.DeserializeObject<dynamic>(tokenContent); // 获取用户信息 var userInfoClient = new HttpClient(); var userInfoResponse = await userInfoClient.GetAsync( $"{authorityserver}/protocol/openid-connect/userinfo?access_token={tokens.access_token}" ); var userInfo = await userInfoResponse.Content.ReadAsStringAsync(); // 构建包含用户声明的身份对象 var identity = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType); identity.AddClaims(n.AuthenticationTicket.Identity.Claims); identity.AddClaim(new Claim("access_token", tokens.access_token)); identity.AddClaim(new Claim("refresh_token", tokens.refresh_token)); // 添加用户信息中的自定义声明 var userClaims = JsonConvert.DeserializeObject<Dictionary<string, object>>(userInfo); foreach (var claim in userClaims) { identity.AddClaim(new Claim(claim.Key, claim.Value.ToString())); } // 更新认证票据 n.AuthenticationTicket = new AuthenticationTicket( new ClaimsIdentity(identity.Claims, n.AuthenticationTicket.Identity.AuthenticationType), n.AuthenticationTicket.Properties ); } } });
简化控制器认证判断
可以替换手动判断逻辑,使用ASP.NET内置的[Authorize]特性自动处理未认证请求:
[Authorize(AuthenticationTypes = "keycloak_auth")] public class HomeController : BaseController { public ActionResult Index() { ViewBag.Title = "Home"; return View(); } }
验证要点
- 确保Keycloak客户端配置中的Valid Redirect URIs包含
http://localhost:13636/home。 - 检查是否引用了
Microsoft.Owin.Security.OpenIdConnect和Newtonsoft.Json包(用于令牌解析)。
内容的提问来源于stack exchange,提问作者user2300947
相关产品推荐
相关产品推荐

