Ручка пружинный исключения проверки подлинности с @ExceptionHandler
Я'м с использованием Spring MVC, О'ы @ControllerAdvice
и @ExceptionHandler
обрабатывать все исключения из API-интерфейса REST. Он отлично работает для исключений, веб-контроллеры в MVC, но это не работает для исключений, весна пользовательские фильтры безопасности, поскольку они выполняются до методов контроллера вызываются.
У меня есть обычай весенней фильтр безопасности, что делает маркер на основе авт:
public class AegisAuthenticationFilter extends GenericFilterBean {
...
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
try {
...
} catch(AuthenticationException authenticationException) {
SecurityContextHolder.clearContext();
authenticationEntryPoint.commence(request, response, authenticationException);
}
}
}
С пользовательской точки входа:
@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
}
}
И этот класс для обработки исключений во всем мире:
@ControllerAdvice
public class RestEntityResponseExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({ InvalidTokenException.class, AuthenticationException.class })
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
@ResponseBody
public RestError handleAuthenticationException(Exception ex) {
int errorCode = AegisErrorCode.GenericAuthenticationError;
if(ex instanceof AegisException) {
errorCode = ((AegisException)ex).getCode();
}
RestError re = new RestError(
HttpStatus.UNAUTHORIZED,
errorCode,
"...",
ex.getMessage());
return re;
}
}
Что мне нужно сделать, это вернуть детальный тело JSON даже для весны AuthenticationException безопасности. Есть ли способ сделать весной AuthenticationEntryPoint безопасности и весна в MVC @ExceptionHandler работать вместе?
Я'м с использованием Spring безопасности 3.1.4 и весна в MVC 3.2.4.
Ок, я попробовал как предложил написать сам JSON из AuthenticationEntryPoint и он работает.
Просто для тестирования я изменил AutenticationEntryPoint, удалив ответ.sendError
Таким образом, вы можете отправить пользовательских данных JSON вместе с 401 несанкционированного даже если вы используете Весна AuthenticationEntryPoint безопасности.
Очевидно, что вы не хотели построить JSON, как я сделал для тестирования, но вы бы сериализовать некоторые экземпляра класса.
Это очень интересная проблема, которая Весна безопасности и весна интернет основы не вполне последователен в том, как они обрабатывать ответ. Я считаю, что это поддерживает обработку сообщений с MessageConverter в удобном виде ошибки.
Я пытался найти элегантный способ, чтобы вставить MessageConverter в Весны безопасности, так что они могли бы поймать исключение и вернуть их в правильный формат в соответствии с содержанием переговоров**. Все-таки, мое решение ниже-это не элегантно, но, по крайней мере, использовать Весна код.
Я предполагаю, что вы умеете включать библиотеку Джексон и JAXB, иначе нет смысла продолжать. Есть 3 шага в общей сложности.
Шаг 1 - создать отдельный класс, хранение MessageConverters
Этот класс не играет никакой магии. Он просто сохраняет преобразователи сообщения и процессор
RequestResponseBodyMethodProcessor
. Магия внутри тот процессор, который будет делать ВСЮ работу, включая согласование содержания и преобразования соответственно тело ответа.Шаг 2 - Создать AuthenticationEntryPoint
Как и во многих учебниках, этот класс необходим, чтобы реализовать пользовательскую обработку ошибок.
Шаг 3 - регистрируем точка входа
Как уже упоминалось, я делаю это с Java конфиг. Я просто показать соответствующие настройки здесь должны быть и другие конфигурации, такие как сессии апатриды и т. д.
Попробовать некоторые проверки подлинности не случае, помните, заголовок запроса должен включать принимаем : ХХХ и вы должны получить исключение в JSON, XML или другие форматы.
Лучший способ я'вэ нашел делегировать исключение из HandlerExceptionResolver
затем вы можете использовать @ExceptionHandler в формат ответа, как вы хотите.
В случае весенних ботинок и
@EnableResourceServer
, он относительно легкий и удобный, чтобы продлитьResourceServerConfigurerAdapter
вместоWebSecurityConfigurerAdapter
в Java конфигурации и зарегистрировать пользовательскийAuthenticationEntryPoint
путем переопределениянастроить(ResourceServerSecurityConfigurer ресурсов) и использования ресурсов.authenticationEntryPoint(customAuthEntryPoint())
внутри метода.Что-то вроде этого:
Там's также хороший
OAuth2AuthenticationEntryPoint
, который может быть продлен (так как он's не окончательной) и частично повторно использован при реализации пользовательскогоAuthenticationEntryPoint
. В частности, он добавляет назальный веб-аутентификации; заголовки с ошибками-подробности.Надеюсь, это поможет кому-то.
Принимая ответы от @Никола и @Виктор крыла и добавив более унифицированной форме:
Теперь, вы можете вводить настроен Джексон, JAXB или что вы используете, чтобы преобразовать органов ответ на ваш MVC в аннотации или XML-конфигурацию в соответствии со своими сериализаторы, десериализаторы и так далее.
Мы должны использовать
HandlerExceptionResolver
в таком случае.Кроме того, нужно добавить в класс обработчик исключений, чтобы вернуть объект.
возможно, вы получите сообщение об ошибке во время выполнения проекта из-за нескольких реализаций
HandlerExceptionResolver
, в этом случае вы должны добавить@квалификатор (на"handlerExceptionResolver", У)
ОHandlerExceptionResolver
Мне удалось справиться путем простого переопределения метода 'unsuccessfulAuthentication' в мой фильтр. Нет, я отправить сообщение об ошибке клиенту с необходимый код состояния HTTP.
Я'м с помощью objectMapper. Каждое служение остальное в основном работает с JSON, и в одном из ваших конфигов вы уже настроили объект сопоставителя.
Код написан в Котлин, надеюсь все будет хорошо.
Обновление: если вы любите и предпочитаете, чтобы увидеть код напрямую, то у меня есть два примера для вас, используя стандартные весенние обеспечения которых является то, что вы ищете, другая-с использованием эквивалента реактивной веб и реактивной безопасности:<БР>
@Подгружен ObjectMapper картографа;
частная статические заключительные регистратор регистратор = LoggerFactory.getLogger(JwtAuthEntryPoint.class);
@Переопределить общественного недействительными начать(HttpServletRequest запросу Ответ HttpServletResponse, AuthenticationException е) бросает IOException, ServletException { // Вызывается, когда пользователь пытается получить доступ к конечной точке, которая требует проверки подлинности // мы просто вернем unauthorizaed логгер.ошибки("от несанкционированного ошибка. Сообщение - {} себе", Эл.метод GetMessage());
ServletServerHttpResponse рез = новый ServletServerHttpResponse(ответ); РЭС.setStatusCode(HttpStatus.Несанкционированный); РЭС.getServletResponse().действие setheader(HttpHeaders.CONTENT_TYPE, тип носителя.APPLICATION_JSON_VALUE); РЭС.getBody().писать(маппер.writeValueAsString(новый ErrorResponse("Вы должны аутентифицироваться на")).метод getbytes()); } } ``
Объектом сопоставления становится зернах после добавления весны веб-стартера, но я предпочитаю, чтобы настроить его, так вот моя реализация для ObjectMapper: ``Ява @Фасоль общественные Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder построитель = новый Jackson2ObjectMapperBuilder(); строитель.модули(новые JavaTimeModule());
// например: использовать created_at вместо createdAt строитель.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
// пропустить пустые поля строитель.serializationInclusion(JsonInclude.Включить.NON_NULL); строитель.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); возвращение строитель; }
В AuthenticationEntryPoint по умолчанию установить в вашем классе WebSecurityConfigurerAdapter:
Ява @Конфигурации @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = истина) общественный класс расширяет SecurityConfig WebSecurityConfigurerAdapter { // ............ @Подгружен частная JwtAuthEntryPoint unauthorizedHandler; @Переопределить охраняемых недействительными настроить(HttpSecurity по HTTP) бросает исключение { протоколу HTTP.CORS (с).и().CSRF атак().отключить() .authorizeRequests() // .antMatchers(" по - /по API/автто", " по - /по API/логини", " в**то").permitAll() .anyRequest().permitAll() .и() .обработка исключений().authenticationEntryPoint(unauthorizedHandler) .и() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.Без гражданства);протоколу HTTP.заголовки().frameOptions().отключить(); // в противном случае Н2 консоль недоступна // Есть много способов способы размещения наш фильтр в цепи // Вы можете устранить любые ошибки включение отладки(см. ниже), он будет печатать цепочки фильтров протоколу HTTP.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); } // .......... } ``