在SpringBoot中配置Filter时使用@Autowired。

8

我需要在一个过滤器中使用自动装配。因此,我使用 @Component 对我的过滤器类进行注释,

import org.springframework.web.filter.GenericFilterBean;
@Component
public class TokenAuthorizationFilter extends GenericFilterBean {
    @Autowired
    public EnrollCashRepository enrollCashRepository;
}

然后我在SecurityConfig中添加了以下过滤器:

   @Configuration
    @EnableWebMvcSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(WebSecurity webSecurity) throws Exception
        {
            webSecurity.ignoring().antMatchers(HttpMethod.GET, "/health");
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterBefore(new TokenAuthorizationFilter(), BasicAuthenticationFilter.class);  
            http.authorizeRequests().antMatchers("/api/**").authenticated();    
    }

我的问题是在使用@Component注解时,我的过滤器会被调用两次。如果我删除@Component注解,它只会被调用一次。

于是我在我的Spring Boot主类中添加了以下修复代码。然后我在SecurityConfig中将addFilterBefore的行注释掉了。

 @Bean
    public FilterRegistrationBean tokenAuthFilterRegistration() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new PITokenAuthorizationFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

然后我的过滤器被调用一次。但是,即使我将setEnabled设置为true或false,当我调用我的rest api时,我仍然会收到403禁止错误,http://localhost:8080/api/myservice

我该如何解决这种情况,以便在我的Spring过滤器中使用@Autowired?

编辑:添加控制器和过滤器类,

@RestController
@RequestMapping(value = "/api")
public class SpringToolController { 
    @RequestMapping(value = "/myservice", method = RequestMethod.GET)
    public HttpEntity<String> myService() {
        System.out.println("-----------myService invoke-----------");
        return new ResponseEntity<String>(HttpStatus.OK);
    }
}



public class TokenAuthorizationFilter extends GenericFilterBean {
    public TokenAuthorizationFilter(EnrollCashRepository enrollCashRepository) {
        this.enrollCashRepository = enrollCashRepository;
    }

    public EnrollCashRepository enrollCashRepository;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("before PITokenAuthorizationFilter");
        chain.doFilter(servletRequest, servletResponse);
        System.out.println("after PITokenAuthorizationFilter");
    }

    public EnrollCashRepository getEnrollCashRepository() {
        return enrollCashRepository;
    }

    public void setEnrollCashRepository(EnrollCashRepository enrollCashRepository) {
        this.enrollCashRepository = enrollCashRepository;
    }

}
2个回答

15

将您的FilterRegistrationBean移除,并在您的SecurityConfig中像这样初始化TokenAuthorizationFilter

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public EnrollCashRepository enrollCashRepository;

    @Override
    public void configure(WebSecurity webSecurity) throws Exception
    {
        webSecurity.ignoring().antMatchers(HttpMethod.GET, "/health");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception 
    {
        http.addFilterBefore(tokenAuthorizationFilter(), BasicAuthenticationFilter.class);  
        http.authorizeRequests().antMatchers("/api/**").authenticated();    
    }

    private TokenAuthorizationFilter tokenAuthorizationFilter() 
    {
        return new TokenAuthorizationFilter(enrollCashRepository);
    }
}

移除 @Autowired@Component 注解,并通过构造函数注入设置您的 EnrollCashRepository

import org.springframework.web.filter.GenericFilterBean;

public class TokenAuthorizationFilter extends GenericFilterBean {

    private final EnrollCashRepository enrollCashRepository;

    public TokenAuthorizationFilter(EnrollCashRepository enrollCashRepository) 
    {
        this.enrollCashRepository = enrollCashRepository
    }
}

谢谢。现在enrollCashRepository正在被填充。但是当我调用rest api时,我会收到403-Forbidden错误。我编辑了答案以显示rest控制器。 - Harshana
请将 org.springframework.security 的日志级别设置为 DEBUG 并将堆栈跟踪添加到您的问题中,谢谢。 - ksokol
它会打印出我添加的过滤器之前和 PITokenAuthorizationFilter 之后的 sys outs。但以上出现的 403 错误来自 REST 端点。 - Harshana
我相信你,但 DEBUG 日志显示了你的 403 的根本原因。 - ksokol
也许 @SpringBootApplication(exclude = SecurityAutoConfiguration.class) 可以帮到您。否则,您的配置似乎从根本上出了问题。 - ksokol
显示剩余5条评论

0

我现在给我的工作类添加了一个测试过滤器,它运行良好。以下是与此相关的代码。

过滤器

@Component
public class TestFilter extends GenericFilterBean {

private static final Logger logger = LoggerFactory.getLogger(TestFilter.class);

@Autowired
UserService userService;

 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     logger.error("=====================AWESOME=======================");
     chain.doFilter(request, response);
     userService.activate("123"); //this works
 }

}

应用程序安全配置

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private TestFilter testFilter;

     @Override
     protected void configure(HttpSecurity http) throws Exception {
     //loginFailureHandler.setDefaultFailureUrl("/login?error=true");
     http.addFilterBefore(testFilter, BasicAuthenticationFilter.class);
     //Http other config here.
 }
}

应用程序配置

@Configuration
@ImportResource({
    "classpath*:/context.xml"
})
@PropertySources(
    @PropertySource({
            "classpath:/application.yml"
    })
)
@Import({AppSecurityConfig.class, WebConfig.class,TestFilter.class})
public class AppConfig {
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接