我正在尝试为403(拒绝访问)和500(内部服务器错误)等错误编写自定义错误页面。它们将从Velocity模板呈现,并使用用户的语言环境翻译所有消息。身份验证和区域设置解析在应用程序中正常工作。
我在web.xml中设置了所需页面的位置,在webmvc-context.xml中我添加了requet-to-view controller。
我遇到的问题是 SecurityContextHolder.getContext()。getAuthentication()在错误页面视图中返回null。看着我看到的日志:
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...
如何才能使正常页面和错误页面的行为相同?
答案 0 :(得分:6)
您遇到的问题是将{1}转换为错误页面的ExceptionTranslationFilter
位于SecurityContextPersistenceFilter
之前,它将身份验证从SecurityContextRepository
中提取出来并放入{ {1}}。请求完成后,SecurityContextHolder
会将信息从SecurityContextPersistenceFilter
中取回。
它清除SecurityContextHolder
的原因是SecurityContextHolder
通常是线程本地的,如果servlet容器要重用一个线程(大多数这样做),他们可能会意外地将这些凭据提供给其他人。
通常SecurityContextHolder
是最外层的过滤器,以避免任何异常未被翻译的风险。
您最好的选择是编写一个自定义ExceptionTranslationFilter
,其中包含ExceptionTranslationFilter
(通常是您提到的HTTP会话),并通过{{1}提供对SecurityContextRepository
的访问权限而不是Authentication
。请记住,如果用户未登录,SecurityContextRepository
仍将为null。
答案 1 :(得分:6)
问题可能是springSecurityFilterChain没有拦截错误。尝试将web.xml中的映射更改为
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>