在 Spring Boot 中配置 RequestContextListener

Posted

技术标签:

【中文标题】在 Spring Boot 中配置 RequestContextListener【英文标题】:Configuring RequestContextListener in SpringBoot 【发布时间】:2015-07-27 01:23:31 【问题描述】:

我有一个使用 Spring-Security 的 Spring-Boot 应用程序。我有一个请求范围的 bean,我想将它自动装配到安全过滤器链中的一个自定义过滤器中,但目前它不起作用。

我了解在 DispatcherServlet 之外使用请求范围的 bean 需要进行一些配置,并且已阅读此 http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other 但尚未取得任何成功:

对于 Servlet 3.0+,这可以通过 WebApplicationInitializer 接口。

(我使用的是最新的 Tomcat,servlet 3+ 也是)

我尝试过同时使用 RequestContextListener 和 RequestContextFilter(文档说它们和 DispatcherServlet 执行完全相同的操作),但在这两种情况下我仍然会遇到错误,因为我的自动装配对象为空:

我尝试注册过滤器

@Configuration
@ComponentScan
@EnableAutoConfiguration
class Application extends SpringBootServletInitializer  

    @Override protected SpringApplicationBuilder configure( SpringApplicationBuilder application ) 
        application.sources( Application )
    

    @Override public void onStartup( ServletContext servletContext ) throws ServletException 
        super.onStartup( servletContext )
        servletContext.addFilter("requestContextFilter", new RequestContextFilter() ).addMappingForUrlPatterns(null, false, "/*")
    

我尝试注册监听器

@Configuration
@ComponentScan
@EnableAutoConfiguration
class Application extends SpringBootServletInitializer  

    @Override protected SpringApplicationBuilder configure( SpringApplicationBuilder application ) 
        application.sources( Application )
    

    @Override public void onStartup( ServletContext servletContext ) throws ServletException 
        super.onStartup( servletContext )
        servletContext.addListener( new RequestContextListener() ) 
    

我是否遗漏了一些明显的东西?我已经查看了 Spring Boot 的自动配置源代码,但还没有遇到任何东西。


更新

我是个白痴,我在我的 SpringSecurity 配置中添加了我的过滤器,在 configure() 方法中:

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

但尚未将新过滤器注册为 Bean。根据下面 M. Denium 的评论,我不需要所有额外的配置显式添加侦听器/过滤器,只需注册 bean 就足够了。

【问题讨论】:

你让它变得复杂。只需添加一个构造RequestContextListener@Bean 方法。 Spring Boot 将完成剩下的工作。但是,由于 Spring 安全过滤器链受 Spring 控制,因此不需要这样做,因此除非您在实际过滤器链之外执行操作,否则您需要注册它,否则它应该可以工作。 谢谢@M.Deinum - 原来我是个白痴 - 我已经用细节更新了问题,但基本上没有正确注册过滤器。 @M.Deinum: 自定义AuthenticationProvider 是否被视为“在实际过滤器链之外”?如果没有,那么这样的提供者是否可以访问已初始化的 RequestContextHolder 而无需显式配置 RequestContextListener 【参考方案1】:

正如更新/cmets 中所详述的,这是我自己的愚蠢造成的。

Spring-Boot 能够将请求/会话范围的 bean 自动装配到 DispatcherServlet 之外的过滤器中。根据 Spring 的文档,我们需要添加 RequestContextListenerRequestContextFilter 以启用此功能:

在请求、会话和全局中支持 bean 的作用域 会话级别(网络范围的 bean),一些小的初始配置是 在定义 bean 之前需要。 (此初始设置不是 标准范围、单例和原型所需的。) ...

如果你在 Spring Web MVC 中访问作用域 bean,实际上是在一个 由 Spring DispatcherServlet 处理的请求,或 DispatcherPortlet,则无需特殊设置: DispatcherServlet 和 DispatcherPortlet 已经公开了所有相关的 状态。

为了处理这个问题,我需要注册一个 RequestContextListener bean:

@Bean public RequestContextListener requestContextListener()
    return new RequestContextListener();
 

如果您不注册该 bean,您将收到一条错误消息,指出您正在尝试访问 DispatcherServlet 之外的 Request 范围。

我遇到的问题(自动装配的对象没有被注入)是因为我只是将我的自定义过滤器注册为标准类实例,而不是 Spring 托管 bean:

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

为了解决这个问题,我只是将 PreAuthFilter 的创建移到了单独的 @Bean 方法中,然后 @Autowired 功能就可以正常工作了。

【讨论】:

谢谢你,不要对自己太苛刻。愚蠢。你的问题和回答真的帮助了我。 谢谢,这对我也有帮助,但我没有注册 RequestContextFilter bean,而是在我的 ResourceServerConfigurerAdaptor 扩展中添加以下行:addFilterAfter(new RequestContextFilter(), CsrfFilter.class)

以上是关于在 Spring Boot 中配置 RequestContextListener的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot实战 Spring常用配置

Spring Boot在aop中获取request对象

spring boot拦截器中获取request post请求中的参数

spring boot拦截器中获取request post请求中的参数

Spring Boot CORS 配置不接受授权标头

spring boot application.properties 配置参数详情