#java #spring #security #spring-webflux #reactive
#ява #весна #Безопасность #пружина-webflux #реактивный #spring-webflux
Вопрос:
Я пытаюсь настроить с помощью пользовательских строковых сообщений Spring webflux security, если вход / выход из системы был успешным или произошел сбой. Обработчики работают, за исключением «authenticationFailureHandler».
В документах упоминается что-то о «logoutSuccessUrl()», но оно не существует, и эти обработчики возвращаются с Mono< Void > .
Итак, у меня есть 2 вопроса:
-
Как мне вернуть некоторую строку в качестве ответа, например, если аутентификация завершается с ошибкой, тогда что-то вроде «Недопустимое имя пользователя или пароль» или какая-либо строка json. Я пытался перенаправить на действие, но я не могу сделать это с помощью void Mono.
-
Почему authenticationFailureHandler не работает, а любой другой обработчик работает? Это ошибка?
-Я попытался перенаправить с помощью Mono.just(«redirect:/some-url»).then(), но это ничего не дало. Для ответов
- Я создал свои обработчики bean, попытался изменить последовательность методов, отключив / включив другие обработчики. Для обработчика ошибок аутентификации.
Вы можете найти весь мой код здесь:https://github.com/iron2414/WebFluxAuth
Это модифицированная версия кода из этой статьи:https://medium.com/@mgray_94552/reactive-authorisation-in-spring-security-943e6534aaeb
Конфигурация безопасности выглядит следующим образом:
return http
.exceptionHandling()
.accessDeniedHandler((swe, e) -> {
System.out.println("ACCESS DENIED");
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
});
})
.authenticationEntryPoint((swe, e) -> {
System.out.println("AUTHENTICATION ENTRTY POINT");
ServerHttpResponse response = swe.getResponse();
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
});
})
.and()
.authorizeExchange()
.pathMatchers("/**").authenticated()
.and()
.formLogin()
.authenticationFailureHandler(MyAuthenticationFailureHandler())
.authenticationSuccessHandler(MyAuthenticationSuccessHandler()).and()
.logout().logoutSuccessHandler(MyLogoutHandler())
.and()
.csrf()
.disable()
.build();
Обработчик loginFailure:
@Bean
public MyAuthenticationFailureHandler MyAuthenticationFailureHandler() {
return new MyAuthenticationFailureHandler();
}
@Component
public class MyAuthenticationFailureHandler implements ServerAuthenticationFailureHandler {
@Override
public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException e) {
//TODO redirect
System.out.println("AUTHENTICATION FAILURE");
return Mono.empty();
}
}
Комментарии:
1. Я создал полнофункциональный пример проекта, реализующего webflux webflux-security, он содержит полный рабочий процесс об обработчиках success failure, вы можете посмотреть здесь: github.com/eriknyk/webflux-jwt-security-demo
Ответ №1:
Для ответа мне пришлось использовать «RedirectServerAuthenticationSuccessHandler» для успешной аутентификации. И я создал точно такой же класс, который реализует сбой.
Не работает обработчик сбоя авторизации — известная проблема. Чтобы заставить его работать, вы должны установить loginpage. Поэтому я просто обновил его до значения по умолчанию «/ login»
Комментарии:
1. эта проблема все еще не решена. но ваш трюк для страницы входа работает 🙂 спасибо
Ответ №2:
Я столкнулся с той же проблемой и в конечном итоге использовал пользовательский defaulterrororwebexceptionhandler для ее решения:
@Component
public class MyGlobalWebExceptionHandler extends DefaultErrorWebExceptionHandler {
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return route(all(), this::renderErrorResponse);
}
@Override
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
ErrorRepresentation representation = createErrorRepresentation(request);
return ServerResponse
.status(representation.getError().getStatus())
.contentType(APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(representation));
}
private ErrorRepresentation createErrorRepresentation(ServerRequest request) {
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
Throwable throwable = getError(request);
if (throwable instanceof AuthenticationException) {
AuthenticationFailureException failureException = new AuthenticationFailureException(throwable.getMessage());
return new ErrorRepresentation(failureException, error.get("path").toString());
}
}
}