无法在Spring中的身份验证筛选器内自动装配服务

时间:2015-09-10 06:11:35

标签: java spring hibernate spring-mvc

我正在尝试通过令牌验证用户,但是当我尝试在TypeError: Cannot use 'in' operator to search for 'function1' in <3> 内自动连接一个我的服务时,我得到空指针异常。 因为自动服务为空,我该如何解决此问题?

我的AuthenticationTokenProcessingFilter班级

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); } }

中添加以下内容
AppConfig

我的AppConfig注释

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

5 个答案:

答案 0 :(得分:34)

您不能使用开箱即用的依赖注入。虽然您使用的是GenericFilterBean,但您的Servlet过滤器不受spring管理。正如javadocs所指出的

  

这个通用过滤器基类不依赖于Spring   org.springframework.context.ApplicationContext概念。过滤器   通常不加载自己的上下文,而是访问服务bean   从Spring根应用程序上下文,可通过过滤器访问   ServletContext(参见   org.springframework.web.context.support.WebApplicationContextUtils)。

用简单的英语我们不能指望spring注入服务,但我们可以在第一次调用时设置它。 E.g。

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 ...    
    }

}

答案 1 :(得分:14)

这是一个足够古老的问题,但我会为那些喜欢我google问题的人添加我的答案。

您必须从GenericFilterBean继承过滤器,并将其标记为Spring @Component

@Component
public class MyFilter extends GenericFilterBean {

    @Autowired
    private MyComponent myComponent;

 //implementation

}

然后在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;
    }
}

这样可以在过滤器中正确地自动装配组件。

答案 2 :(得分:3)

如果您的过滤器类扩展了GenericFilterBean,您可以通过这种方式在应用程序上下文中获取对bean的引用:

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");
}

对于那些不喜欢硬编码bean名称或需要在过滤器中注入多个bean引用的人来说,这是不太明确的方式:

@Autowired
private YourBeanToInject yourBeanToInject;

@Override
public void initFilterBean() throws ServletException{

    SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());

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

答案 3 :(得分:1)

您可以配置bean过滤器并根据需要传递参数。我知道Spring的上下文中有过滤器,你无法获得spring的自动扫描所依赖的依赖注入。但不是100%确定是否有一个花哨的注释,你可以把你的过滤器做一些神奇的东西

   <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>

然后在spring.xml中注入bean

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

答案 4 :(得分:0)

我参加聚会很晚,但是这种解决方案对我有用。

在web.xml中添加一个ContextLoaderListener。 applicationContext可以具有依赖项bean。

<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>

然后在MyFilter中添加SpringBeanAutowiringSupport processInjectionBasedOnServletContext,这会将web应用程序上下文添加到过滤器中,从而添加所有依赖项。

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

}