web-dev-qa-db-fra.com

Configurer RequestContextListener dans Spring Boot

J'ai une application Spring-Boot qui utilise Spring-Security. J'ai un bean de portée de demande que je veux câbler automatiquement dans l'un de mes filtres personnalisés dans la chaîne de filtres de sécurité, mais pour le moment cela ne fonctionne pas.

Je comprends qu'une certaine configuration est nécessaire pour utiliser des beans de portée de demande en dehors de DispatcherServlet, et j'ai lu ceci http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html /beans.html#beans-factory-scopes-other Mais n'ont pas encore réussi:

Pour Servlet 3.0+, cela peut être fait par programme via l'interface WebApplicationInitializer.

(J'utilise la dernière Tomcat, tout comme la servlet 3+)

J'ai essayé d'utiliser à la fois le RequestContextListener et le RequestContextFilter (les documents disent qu'ils et le DispatcherServlet font exactement la même chose), mais dans les deux cas, j'obtiens toujours des erreurs car mon objet auto-câblé est nul:

Ma tentative d'enregistrement du filtre

@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, "/*")
    }

Ma tentative d'enregistrement de l'écouteur

@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() ) 
    }

Suis-je en train de manquer quelque chose d'évident? J'ai jeté un œil au code source de la configuration automatique pour Spring Boot et je n'ai encore rien trouvé.


[~ # ~] mise à jour [~ # ~]

J'étais un idiot, j'avais ajouté mon filtre dans ma configuration SpringSecurity, à l'intérieur de la méthode configure():

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

mais n'avait pas enregistré le nouveau filtre en tant que bean. Selon le commentaire de M. Denium ci-dessous, je n'avais pas besoin de toute cette configuration supplémentaire ajoutant explicitement l'écouteur/filtre, il suffit d'enregistrer le bean.

33
rhinds

Comme détaillé dans la mise à jour/commentaires, cela a été causé par ma propre stupidité.

Spring-Boot est capable de câbler automatiquement les beans de portée de demande/session dans des filtres qui sont en dehors de DispatcherServlet Selon la documentation de Spring, nous devons ajouter RequestContextListener ou RequestContextFilter pour activer cette fonctionnalité:

Pour prendre en charge la portée des beans aux niveaux de la demande, de la session et de la session globale (beans de portée Web), une configuration initiale mineure est requise avant de définir vos beans. (Cette configuration initiale n'est pas requise pour les étendues standard, singleton et prototype.) ...

Si vous accédez aux beans étendus dans Spring Web MVC, en effet, dans une demande qui est traitée par Spring DispatcherServlet ou DispatcherPortlet, aucune configuration spéciale n'est nécessaire: DispatcherServlet et DispatcherPortlet exposent déjà tous les états pertinents.

Pour gérer cela, j'avais besoin d'enregistrer un bean RequestContextListener:

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

Si vous n'enregistrez pas ce bean, vous obtiendrez une erreur indiquant que vous essayez d'accéder à l'étendue de la demande en dehors de DispatcherServlet.

Le problème que j'ai rencontré (les objets câblés automatiquement ne sont tout simplement pas injectés) est dû au fait que je viens d'enregistrer mon filtre personnalisé en tant qu'instance de classe standard, et non en tant que bean géré par Spring:

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

Pour résoudre ce problème, je viens de déplacer la création du PreAuthFilter vers un sepearte @Bean, la méthode @Autowired la fonctionnalité a bien fonctionné.

50
rhinds