Я пытаюсь реализовать механизм logout
, инициированный конечным пользователем.
У меня задействовано 4 основных субъекта.
Angular
приложение, зарегистрированное как общедоступный OIDC
клиент на Keycloak.Spring Boot
приложение с защищенной REST
конечной точкой.Когда конечный пользователь инициирует logout
, приложение Angular
вызывает end_session_endpoint
Keycloak. Я настроил URL-адрес logout
для своего поставщика удостоверений (Spring Authorization Server
) в Keycloak как http://localhost:9000/logout, который является конечной точкой выхода Spring Security
по умолчанию.
К вашему сведению: я не включил BackChannel
или FrontChannel
выход из системы.
На вкладке Network
в Developer Console
последовательность вызовов происходит, как показано ниже:
При проверке журналов DEBUG
в Spring Authorization Server
я вижу, что logout
происходит для этого конкретного конечного пользователя, включая аннулирование JSESSIONID
, однако сеанс не завершается в Keycloak, что заставляет пользователя оставаться в системе и получать доступ к защищенному REST
конечная точка.
Ожидается ли, что Spring Authorization Server
вернет Keycloak определенный ответ, чтобы сообщить, что процесс logout
завершен в конце и что Keycloak может завершить сеанс сейчас?
Это моя логика для logout
в 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 завершил сеанс в конце. Любые выводы будут высоко оценены.
Спасибо!
Обновление: параметр 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
Получил это, чтобы работать наконец!
logoutSuccessUrl("http://localhost:4200")
неверно.
Как я упоминал в разделе «Обновление» моего вопроса, Keycloak отправляет параметр post_logout_redirect_uri
(проверил конечную точку logout
в вызовах Network
в Chrome Developer Console
), logoutSuccessUrl
или redirectUri
следует установить на
http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response
Также обратите внимание, что приведенный выше URL-адрес принимает state
в качестве параметра запроса. Сначала он поставил мне 400 Bad Request
, так как я не отправил state
.
Поскольку мне нужно было перехватывать параметр state
, когда logout
инициируется в Spring Authorization Server
, я добавил собственный обработчик выхода из системы, чтобы выполнить эту работу.
@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);