Spring SecurityContext возвращает нулевую аутентификацию на страницах ошибок

Я пытаюсь написать пользовательскую страницу ошибок для ошибок, таких как 403 (доступ запрещен) и 500 (внутренняя ошибка сервера). Они будут отображаться из шаблона Velocity, и все сообщения будут переведены с использованием языка пользователя. Аутентификация и разрешение локали прекрасно работает в приложении.

Я установил местоположение в web.xml как желаемую страницу, а в webmvc-context.xml добавил контроллер для просмотра заявок через.

Проблема, с которой я столкнулся, заключается в том, что SecurityContextHolder.getContext(). GetAuthentication() возвращает нулевое значение в представлении страницы с ошибкой. Глядя на бревно я увидел:

06.10 14:42:26 DEBUG - context.HttpSessionSecurityContextRepository(HttpSessionSecurityContextRepository.java:351) -  - SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@ece7b0b7: Authentication: ...
06.10 14:42:26 DEBUG - context.SecurityContextPersistenceFilter(SecurityContextPersistenceFilter.java:89) -  - SecurityContextHolder now cleared, as request processing completed
06.10 14:42:26 DEBUG - servlet.DispatcherServlet(DispatcherServlet.java:691) -  - DispatcherServlet with name 'foo' processing GET request for [/foo/app/error/403.html]

Поэтому Spring или Tomcat перенаправляют на страницу с ошибкой, и жест запроса завершается, поэтому контекст очищается. И новый "запрос" не подвергается фильтрам Spring Security, поэтому не восстанавливает контекст.

Обычный способ не работает, но кажется, что информация аутентификации находится где-то в сеансе, также потому что AbstractTemplateView регистрирует следующее:

Exposing session attribute 'SPRING_SECURITY_CONTEXT' with value [org.springframework.security.core.context.SecurityContextImpl@edfbd958: Authentication: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@edfbd958...

Как правильно получить, чтобы и обычные страницы, и страницы с ошибками работали одинаково?

2 ответа

Решение

Проблема, с которой вы сталкиваетесь, заключается в том, что ExceptionTranslationFilter который переводит исключения в страницы ошибок до SecurityContextPersistenceFilter который вытягивает аутентификацию из SecurityContextRepository и кладет его в SecurityContextHolder, Когда запрос завершает SecurityContextPersistenceFilter забирает информацию из SecurityContextHolder,

Причина, по которой это очищает SecurityContextHolder это то, что SecurityContextHolder обычно является локальным потоком, и если контейнер сервлета будет повторно использовать поток (большинство так делают), они могут случайно передать эти учетные данные кому-то другому.

Типично ExceptionTranslationFilter является внешним фильтром, чтобы избежать риска того, что исключения не будут переведены.

Лучше всего, чтобы вы написали ExceptionTranslationFilter который принимает в SecurityContextRepository (часто HTTP-сессия, как вы упомянули) и обеспечивает доступ к Authentication через SecurityContextRepository а не SecurityContextHolder, Имейте в виду, что Authentication будет по-прежнему нулевым, если пользователь не вошел в систему.

Проблема может заключаться в том, что springSecurityFilterChain не перехватывает ОШИБКИ. Попробуйте изменить отображение в файле web.xml, чтобы оно

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
Другие вопросы по тегам