web-dev-qa-db-fra.com

Impossible de câbler automatiquement le service dans mon filtre d'authentification au printemps

J'essaie d'authentifier l'utilisateur par jeton, mais lorsque j'essaie de câbler automatiquement mes services à l'intérieur de AuthenticationTokenProcessingFilter, j'obtiens une exception de pointeur nul. car le service câblé automatiquement est nul, comment puis-je résoudre ce problème?

Ma classe AuthenticationTokenProcessingFilter

@ComponentScan(basePackages = {"com.marketplace"})
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

    @Autowired
    @Qualifier("myServices")
    private MyServices service;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        @SuppressWarnings("unchecked")
        Map<String, String[]> parms = request.getParameterMap();

        if (parms.containsKey("token")) {
            try {
                String strToken = parms.get("token")[0]; // grab the first "token" parameter

                User user = service.getUserByToken(strToken);
                System.out.println("Token: " + strToken);

                DateTime dt = new DateTime();
                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
                DateTime createdDate = fmt.parseDateTime(strToken);
                Minutes mins = Minutes.minutesBetween(createdDate, dt);


                if (user != null && mins.getMinutes() <= 30) {
                    System.out.println("valid token found");

                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

                    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword());
                    token.setDetails(new WebAuthenticationDetails((HttpServletRequest) request));
                    Authentication authentication = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword(), authorities); //this.authenticationProvider.authenticate(token);

                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }else{
                    System.out.println("invalid token");
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("no token found");
        }
        // continue thru the filter chain
        chain.doFilter(request, response);
    }
}

J'ai essayé d'ajouter follwing dans mon AppConfig

@Bean(name="myServices")
    public MyServices stockService() {
        return new MyServiceImpl();
    }

Mes annotations AppConfig sont

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {
45
Raghu Chandra

Je viens de le faire fonctionner en ajoutant

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this);

Je ne sais pas pourquoi nous devrions le faire même lorsque j'ai essayé d'ajouter un qualificatif explicite. et maintenant le code ressemble

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

        @SuppressWarnings("unchecked")
        Map<String, String[]> parms = request.getParameterMap();

        if (parms.containsKey("token")) {
18
Raghu Chandra

Vous ne pouvez pas utiliser l'injection de dépendance à partir d'un filtre prêt à l'emploi. Bien que vous utilisiez GenericFilterBean, votre filtre de servlet n'est pas géré au printemps. Comme l'ont noté les javadocs

Cette classe de base de filtre générique ne dépend pas du concept Spring org.springframework.context.ApplicationContext. Les filtres ne chargent généralement pas leur propre contexte mais accèdent plutôt aux beans de service à partir du contexte de l'application racine Spring, accessible via le ServletContext du filtre (voir org.springframework.web.context.support.WebApplicationContextUtils).

En clair, nous ne pouvons pas nous attendre à ce que le printemps injecte le service, mais nous pouvons paresseusement le régler au premier appel. Par exemple.

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
    private MyServices service;
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if(service==null){
            ServletContext servletContext = request.getServletContext();
            WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            service = webApplicationContext.getBean(MyServices.class);
        }
        your code ...    
    }

}
41
Haim Raman

C'est une question assez ancienne, mais je vais ajouter ma réponse pour ceux qui m'aiment google ce problème.

Vous devez hériter votre filtre de GenericFilterBean et le marquer comme Spring @Component

@Component
public class MyFilter extends GenericFilterBean {

    @Autowired
    private MyComponent myComponent;

 //implementation

}

Et puis enregistrez-le dans le contexte de Spring:

@Configuration
public class MyFilterConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Autowired
    private MyFilter myFilter;

    @Bean
    public FilterRegistrationBean myFilterRegistrationBean() {
        FilterRegistrationBean regBean = new FilterRegistrationBean();
        regBean.setFilter(myFilter);
        regBean.setOrder(1);
        regBean.addUrlPatterns("/myFilteredURLPattern");

        return regBean;
    }
}

Cela permet de câbler correctement vos composants dans le filtre.

16
Yuriy Kovalek

Si votre classe de filtre étend GenericFilterBean, vous pouvez obtenir une référence à un bean dans le contexte de votre application de cette façon:

public void initFilterBean() throws ServletException {

@Override
public void initFilterBean() throws ServletException {

        WebApplicationContext webApplicationContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        //reference to bean from app context
        yourBeanToInject = webApplicationContext.getBean(yourBeanToInject.class);

        //do something with your bean
        propertyValue = yourBeanToInject.getValue("propertyName");
}

Et voici un moyen moins explicite pour ceux qui n'aiment pas le codage en dur des noms de bean ou qui ont besoin d'injecter plus d'une référence de bean dans le filtre:

@Autowired
private YourBeanToInject yourBeanToInject;

@Override
public void initFilterBean() throws ServletException{

    SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());

    //do something with your bean
    propertyValue = yourBeanToInject.getValue("propertyName");
}
3
Igor Vash

Vous pouvez configurer votre filtre bean et passer en paramètre tout ce dont vous avez besoin. Je sais que dans le contexte de Spring où se trouve le filtre, vous ne pouvez pas obtenir l'injection de dépendance que fait l'auto-scan de Spring. Mais je ne suis pas sûr à 100% s'il y a une annotation de fantaisie que vous pouvez mettre dans votre filtre pour faire des trucs magiques

   <filter>
   <filter-name>YourFilter</filter-name>
       <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

<filter-mapping>
   <filter-name>YourFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

puis injectez le haricot au printemps.xml

  <bean id="YourFilter" class="com.YourFilter">
     <property name="param">
        <value>values</value>
     </property>
  </bean>
1
paul

Je suis en retard à la fête mais cette solution a fonctionné pour moi.

Ajoutez un ContextLoaderListener dans web.xml. applicationContext peut avoir des beans de dépendance.

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

Ajoutez ensuite MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContext qui ajoutera le webapplicationcontext dans le filtre qui ajoutera toutes les dépendances.

@Component
public class MyFilter implements Filter {

    @Autowired
    @Qualifier("userSessionServiceImpl")
    private UserSessionService userSessionServiceImpl;

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain 
    chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        if (userSessionServiceImpl == null) {
            ServletContext context = httpRequest.getSession().getServletContext();
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, context);
    }

       .... (for brevity)
    }

}

0
user9059436