我实现了一个 OncePerRequestFilter
,在 doFilterInternal()
中,我想使用一个利用率类,该类使用了 JdbcTemplate
和来自属性文件的用户数据。我意识到它无法访问属性文件(数据库连接和变量)中的数据并且始终具有空值。正如我在互联网上发现的那样,因为上下文不同。
我可以在本地成功设置一个新的 jdbc 数据源,但我不想复制代码,所以我想像在 RestControllers (@Value
, @Autowired
).
任何想法,我如何将这些注入到将在 servlet 过滤器中使用或直接在我的过滤器中使用的利用类中?
谢谢!
更新 - 代码片段:
在RestController
中,JdbcTemplate
的注入工作正常,但在过滤器中我无法注入它,总是抛出nullPointerException
。
@SpringBootApplication
public class AsdApplication {
public static void main(String[] args) {
SpringApplication.run(AsdApplication.class, args);
}
public static class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegateFilterProxy = new DelegatingFilterProxy();
delegateFilterProxy.setTargetBeanName("MyFilter");
return new Filter[] { delegateFilterProxy };
}
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return null;
}
}
}
@RestController
public class RestCtrl {
@Autowired
private JdbcTemplate jdbcTemplate;
@GetMapping("/test")
public ResponseEntity<String> getTest() {
String result = jdbcTemplate.queryForObject("<query>", String.class);
System.out.println("result in ctrl: " + result);
return new ResponseEntity<>("asd ad asd asd asd", HttpStatus.OK);
}
}
@Component(value = "MyFilter")
public class MyFilter extends OncePerRequestFilter {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String result = jdbcTemplate.queryForObject("<query>", String.class);
System.out.println("result in filter: " + result);
User currentUser = new User("username", "password", new ArrayList<>());
UsernamePasswordAuthenticationToken authenticatedUser = new UsernamePasswordAuthenticationToken(
currentUser, null, currentUser.getAuthorities()
);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
filterChain.doFilter(request, response);
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests().anyRequest().authenticated();
httpSecurity.addFilterBefore(new MyFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
spring.datasource.url=jdbc:<sqlserver>
spring.datasource.username=<user>
spring.datasource.password=<pass>
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
答案 0 :(得分:1)
由于您实际上正在使用 Spring Boot 并希望使其成为 Spring Security 过滤器链的一部分(这是不同的!)您需要做的是
@Bean
方法来创建过滤器并使其成为一个 bean@Bean
方法并添加一个 FilterRegistration
bean 以防止该 bean 被 Spring Boot 注册为过滤器@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests().anyRequest().authenticated();
httpSecurity.addFilterBefore(myFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
@Bean
public MyFilter myFilter() {
return new MyFilter();
}
@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistationBean() {
FilterRegistationBean frb = new FilterRegistrationBean(myFilter());
frb.setEnabled(false);
return frb;
}
最后从您的 @Component
中删除 MyFilter
,因为您不需要它,它会创建一个额外的实例。之前的所有更改(例如 ApplicationInitializer
等,您可以删除。
注意:当您使用 Spring Security 并以某种方式使用它进行身份验证时,而不是扩展 OncePerRequestFilter
我建议您扩展 Spring Security AbstractAuthenticationProcessingFilter
,它可以更好地与 Spring 集成安全性(例如为身份验证、日志记录等触发事件)。
答案 1 :(得分:0)
我看到您正在创建一个 MyFilter
的新实例,而不是使用 Spring 与 @Component(value = "MyFilter")
管理的实例
httpSecurity.addFilterBefore(new MyFilter(), UsernamePasswordAuthenticationFilter.class);
因此您将遇到 NPE,因为 jdbcTemplate
为空。您可以注入由 Spring 管理的实例,而不是创建一个新实例。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("MyFilter")
private MyFilter myFilter;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests().anyRequest().authenticated();
httpSecurity.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
}
}
答案 2 :(得分:-1)
你应该使用这个:
通过这个类,你可以在非 Bean 类中获得不同的 Spring Boot Bean。
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
然后在创建它之后,以这种方式获取您的 bean:
ApplicationContext appCtx = ApplicationContextUtils.getApplicationContext();
// Here you get your dependency
ARequiredClass dependency = appCtx.getBean(ARequiredClass.class);