Spring Authorization Server登出后Keycloak用户会话未终止问题
核心实体
- Client:在Keycloak上注册为公共OIDC客户端的Angular应用
- Keycloak:身份代理服务
- Spring Authorization Server:在Keycloak上注册的身份提供商
- Resource Server:带有安全REST端点的Spring Boot应用
登出流程配置与执行情况
终端用户触发登出时,Angular应用会调用Keycloak的end_session_endpoint。已在Keycloak中将Spring Authorization Server(身份提供商)的登出URL配置为Spring Security默认登出端点http://localhost:9000/logout,且未启用BackChannel或FrontChannel登出。
开发者控制台Network标签显示的调用序列:
http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/protocol/openid-connect/logout?client_id=hello-world&post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A4200%2F&id_token_hint=..http://localhost:9000/logout?state=ff57bb5b-4a79-4e68-bd39-fe7a33ec8788&id_token_hint=...&post_logout_redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Fauth%2Frealms%2FSpringBootKeycloak%2Fbroker%2Foidc%2Fendpoint%2Flogout_response
查看Spring Authorization Server的DEBUG日志,确认终端用户的登出已执行(包括JSESSIONID失效),但Keycloak中的会话未终止,导致用户仍保持登录状态并可访问安全REST端点。
疑问
Spring Authorization Server是否需要向Keycloak返回特定响应,告知自身登出流程已完成,从而让Keycloak终止会话?
当前Spring Authorization Server登出配置
@Bean @Order(Ordered.LOWEST_PRECEDENCE) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests( authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated()) .formLogin(form -> form.loginPage("/login").permitAll()) .addFilterAfter(cookieFilter, ChannelProcessingFilter.class) .logout().logoutSuccessUrl("http://localhost:4200"); return http.build(); }
目前完全不清楚需要配置什么才能让Keycloak终止会话,请求提供解决思路。
更新信息
向Spring Authorization Server发送的登出请求中包含post_logout_redirect_uri参数,但未发生向该URI的重定向,这可能是Keycloak会话未终止的原因:
post_logout_redirect_uri=http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
解决方案思路
动态处理登出重定向:当前配置的
logoutSuccessUrl("http://localhost:4200")硬编码了重定向地址,直接忽略了请求中的post_logout_redirect_uri参数。Keycloak需要Spring Authorization Server登出完成后,重定向回指定的logout_response端点,这样Keycloak才能感知上游身份提供商的登出操作,进而终止自身会话。修改登出配置如下:.logout(logout -> logout .logoutSuccessHandler((request, response, authentication) -> { String redirectUri = request.getParameter("post_logout_redirect_uri"); if (redirectUri != null && !redirectUri.isEmpty()) { response.sendRedirect(redirectUri); } else { response.sendRedirect("http://localhost:4200"); // 默认 fallback 地址 } }) )验证重定向URI合法性:确保Spring Authorization Server允许重定向到Keycloak的
logout_response端点,避免因安全限制拦截该重定向操作。可以配置允许的重定向列表,或在当前场景下直接信任该特定URI。检查Keycloak身份提供商配置:确认Keycloak中身份提供商的登出配置是否正确,比如是否开启了"Forward Logout"相关选项,确保Keycloak会等待上游身份提供商的登出回调后,再终止自身会话。
遵循OIDC登出规范:Spring Authorization Server作为OIDC身份提供商,登出时需严格遵循OIDC RP-Initiated Logout规范,正确处理
id_token_hint和post_logout_redirect_uri参数,确保响应符合规范,让Keycloak能正确处理后续流程。
内容的提问来源于stack exchange,提问作者nehacharya

