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>