У меня есть следующее LogoutResource
, которое хорошо работает с Spring Boot 2.2 при использовании Spring MVC:
@RestController
public class LogoutResource {
private ClientRegistration registration;
public LogoutResource(ClientRegistrationRepository registrations) {
this.registration = registrations.findByRegistrationId("oidc");
}
/**
* {@code POST /api/logout} : logout the current user.
*
* @param request the {@link HttpServletRequest}.
* @param idToken the ID token.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and a body with a global logout URL and ID token.
*/
@PostMapping("/api/logout")
public ResponseEntity<?> logout(HttpServletRequest request,
@AuthenticationPrincipal(expression = "idToken") OidcIdToken idToken) {
String logoutUrl = this.registration.getProviderDetails()
.getConfigurationMetadata().get("end_session_endpoint").toString();
Map<String, String> logoutDetails = new HashMap<>();
logoutDetails.put("logoutUrl", logoutUrl);
logoutDetails.put("idToken", idToken.getTokenValue());
request.getSession().invalidate();
return ResponseEntity.ok().body(logoutDetails);
}
}
Клиент Angular получает этот ответ и перенаправляет его в Keycloak для выхода из системы. Это все прекрасно работает.
logout(): void {
this.authServerProvider.logout().subscribe((logout: Logout) => {
let logoutUrl = logout.logoutUrl;
const redirectUri = `${location.origin}${this.location.prepareExternalUrl('/')}`;
// if Keycloak, uri has protocol/openid-connect/token
if (logoutUrl.includes('/protocol')) {
logoutUrl = logoutUrl + '?redirect_uri=' + redirectUri;
} else {
// Okta
logoutUrl = logoutUrl + '?id_token_hint=' + logout.idToken + '&post_logout_redirect_uri=' + redirectUri;
}
window.location.href = logoutUrl;
});
}
Теперь я пытаюсь изменить его, чтобы он работал с Spring WebFlux. Кажется, что следующее работает и возвращает ожидаемый ответ (я подтвердил это, напечатав значения в моем Angular logout()
методе).
@RestController
public class LogoutResource {
private Mono<ClientRegistration> registration;
public LogoutResource(ReactiveClientRegistrationRepository registrations) {
this.registration = registrations.findByRegistrationId("oidc");
}
/**
* {@code POST /api/logout} : logout the current user.
*
* @param idToken the ID token.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and a body with a global logout URL and ID token.
*/
@PostMapping("/api/logout")
public Mono<Map<String, String>> logout(@AuthenticationPrincipal(expression = "idToken") OidcIdToken idToken) {
return this.registration.map(oidc ->
oidc.getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString())
.map(logoutUrl -> {
Map<String, String> logoutDetails = new HashMap<>();
logoutDetails.put("logoutUrl", logoutUrl);
logoutDetails.put("idToken", idToken.getTokenValue());
SecurityContextHolder.clearContext();
return logoutDetails;
});
}
}
Вы могли заметить, что я попытался использовать SecurityContextHolder.clearContext()
вместо request.getSession().invalidate()
. Кажется, это не работает, потому что пользователь все еще вошел в систему. Есть идеи, что мне нужно сделать, чтобы завершить сеанс безопасности пользователя с помощью WebFlux?