Java Spring SecurityContext在错误页上返回空身份验证

Java Spring SecurityContext在错误页上返回空身份验证,java,spring,authentication,spring-security,Java,Spring,Authentication,Spring Security,我正在尝试为403(拒绝访问)和500(内部服务器错误)等错误编写自定义错误页。它们将从Velocity模板呈现,并使用用户的区域设置翻译所有消息。身份验证和区域设置解析在应用程序中运行良好 我在web.xml中将location设置为所需的页面,并在webmvc-context.xml中通过添加requet来查看控制器 我遇到的问题是SecurityContextHolder.getContext().getAuthentication()在错误页面视图中返回null。看着日志,我看到: 06

我正在尝试为403(拒绝访问)和500(内部服务器错误)等错误编写自定义错误页。它们将从Velocity模板呈现,并使用用户的区域设置翻译所有消息。身份验证和区域设置解析在应用程序中运行良好

我在web.xml中将location设置为所需的页面,并在webmvc-context.xml中通过添加requet来查看控制器

我遇到的问题是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重定向到一个错误页面,请求gest完成,因此上下文被清除。而且新的“请求”不接受Spring安全过滤器,因此不会恢复上下文

通常的方法不起作用,但身份验证信息似乎在会话中的某个位置,这也是因为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...

如何正确获取异常以使正常页面和错误页面的行为相同?

您遇到的问题是,将异常转换为错误页面的
ExceptionTranslationFilter
位于将身份验证从
SecurityContextRepository
并将其放入
SecurityContextHolder
。当请求完成时,
SecurityContextPersistenceFilter
将信息从
SecurityContextHolder
中取出

它清除
SecurityContextHolder
的原因是
SecurityContextHolder
通常是线程本地的,如果servlet容器要重用线程(大多数这样做),它们可能会意外地将这些凭据提供给其他人

通常,
ExceptionTranslationFilter
是最外层的过滤器,以避免任何异常无法转换的风险


您最好的选择可能是编写一个自定义的
ExceptionTranslationFilter
,它接收
SecurityContextRepository
(通常是您提到的HTTP会话),并通过
SecurityContextRepository
而不是
SecurityContextHolder
提供对
身份验证的访问。请记住,如果用户未登录,
身份验证
仍将为空。

问题可能是springSecurityFilterChain没有拦截错误。尝试将web.xml中的映射更改为

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

springSecurityFilterChain
/*
要求
错误

谢谢!我接受了你的答案,因为它给了我正确的输入:
ExceptionTranslationFilter
是处理异常的人。它具有
accessDeniedHandler
属性,默认情况下该属性是
AccessDeniedHandlerImpl
的实例。幸运的是,它有一个
errorPage
属性,文档中说,“作为一个“转发”,将继续填充
SecurityContextHolder
。”我重新布线了bean,它成功了!这让它为我工作错误页面现在知道你是否登录