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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6305801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 15:17:54  来源:igfitidea点击:

Spring SecurityContext returning null authentication on error pages

javaspringauthenticationspring-security

提问by Infeligo

I am trying to write a custom error page for errors like 403 (access denied) and 500 (internal server error). They would be rendered from Velocity template and have all messages translated using user's locale. Authentication and locale resolution works fine in the application.

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

I set up location in web.xml to be the desired page and in webmvc-context.xml I added requet-to-view controller via .

我将 web.xml 中的位置设置为所需的页面,并在 webmvc-context.xml 中通过 .

The problem I ran into is that SecurityContextHolder.getContext().getAuthentication()returns null in the error page view. Looking at the log I saw:

我遇到的问题是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]

So either Spring or Tomcat redirect to an error page and the request gest finalized, thus the context is cleared. And the new "request" doesn't undergo Spring Security filters, thus not restoring the context.

因此,Spring 或 Tomcat 重定向到错误页面并且请求最终确定,因此上下文被清除。并且新的“请求”不会经过 Spring Security 过滤器,因此不会恢复上下文。

The usual way doesn't work, but it seems that the authentication information is somewhere in the session, also because AbstractTemplateView logs the following:

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

How do I properly get so that both normal and error pages would act the same?

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

采纳答案by Pace

The problem you're running into is that the ExceptionTranslationFilterwhich translates exceptions into error pages comes before the SecurityContextPersistenceFilterwhich pulls the authentication out of the SecurityContextRepositoryand puts it into the SecurityContextHolder. When the request finishes the SecurityContextPersistenceFiltertakes the information back out of the SecurityContextHolder.

您正在运行到的问题是,ExceptionTranslationFilter它转换成例外的错误页面来了之前SecurityContextPersistenceFilter它拉出来认证的SecurityContextRepository,并把它放入SecurityContextHolder。当请求完成时,SecurityContextPersistenceFilter将信息从SecurityContextHolder.

The reason it clears the SecurityContextHolderis that the SecurityContextHolderis typically thread local and if the servlet container were to reuse a thread (most do this) they might accidentally give those credentials to someone else.

它清除的原因SecurityContextHolder是,SecurityContextHolder通常线程局部,如果servlet容器是重复使用一个线程(多数这样做),他们可能会不小心给那些凭据给别人。

Typically the ExceptionTranslationFilteris the outermost filter to avoid the risk of any exceptions not getting translated.

通常ExceptionTranslationFilter是最外面的过滤器,以避免任何异常没有被翻译的风险。

Your best bet is to probably write a custom ExceptionTranslationFilterwhich takes in the SecurityContextRepository(often the HTTP session as you mentioned) and provides access to the Authenticationvia the SecurityContextRepositoryand not the SecurityContextHolder. Keep in mind that the Authenticationwill still be null if the user isn't logged in.

最好的办法是到可能编写自定义ExceptionTranslationFilter这需要在SecurityContextRepository(正如你所提到经常HTTP会话),并提供了访问Authentication通过SecurityContextRepository,而不是SecurityContextHolder。请记住,Authentication如果用户未登录,则仍然为空。

回答by Ankur Raiyani

The problem may be that springSecurityFilterChain is not intercepting ERRORS. Try changing your mapping in web.xml to be

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

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