Spring Security 在Spring授权服务器上注销不会终止Keycloak中的用户会话

p4rjhz4m  于 2022-12-13  发布在  Spring
关注(0)|答案(1)|浏览(280)

我正在尝试实现一个最终用户启动的logout机制。
我有4个主要实体参与其中。

***客户端:**在Keycloak上注册为公共OIDC客户端的Angular应用程序
***Keycloak:**充当身份代理
***Spring授权服务器:**在Keycloak上注册的身份提供者
***资源服务器:**具有安全REST端点的Spring Boot应用程序

当最终用户启动logout时,Angular应用程序将调用Keycloak的end_session_endpoint。我已在Keycloak中将我的身份提供者(Spring Authorization Server)的logout URL配置为http://localhost:9000/logout,这是默认的Spring Security注销端点。

**仅供参考:**我尚未启用BackChannelFrontChannel注销.

Developer ConsoleNetwork选项卡中,调用顺序如下:

在检查Spring Authorization Server中的DEBUG日志时,我能够看到该特定最终用户发生了logout,包括使JSESSIONID无效,但会话未在Keycloak中终止,这导致用户保持登录状态并访问安全的REST端点。
Spring Authorization Server是否需要向Keycloak返回一个特定响应,以传达logout进程在结束时已完成,Keycloak现在可以结束会话?
这是我在Spring Authorization Server上的logout的逻辑。

@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结束会议在它的结束。任何线索将不胜感激。
谢谢你,谢谢你

更新:post_logout_redirect_uri参数在logout请求中发送到Spring Authorization Server。我无法看到重定向到此URI,这可能是Keycloak会话未终止的原因。

post_logout_redirect_uri=http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
0ejtzxu1

0ejtzxu11#

终于成功了!
logoutSuccessUrl("http://localhost:4200")不正确。
正如我在问题的Update部分提到的,Keycloak发送了一个post_logout_redirect_uri参数(在Chrome Developer Console中检查了Network调用中的logout端点),logoutSuccessUrlredirectUri应设置为
http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
另外,请注意上面的URL将state作为请求参数。最初,它给了我一个400 Bad Request,因为我没有发送state
由于在Spring Authorization Server上启动logout时,我需要截获state参数,因此我添加了一个自定义注销处理程序来完成这项工作。

@Component
public class IdpLogoutHandler implements LogoutHandler {

    private static final String STATE = "state";

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        String state = request.getParameter(STATE);
        try {
            response.sendRedirect(
                    "http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response?state="
                            + state);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

更新的WebSecurityConfig

http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(
                        authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated())
                .formLogin(form -> form.loginPage("/login").permitAll())
                .addFilterAfter(cookieFilter, ChannelProcessingFilter.class).logout()
                .addLogoutHandler(customLogoutHandler);

相关问题