Using Spring Security with thread pools leads to a race condition when threads are reused
我有一个使用RxJava编写的spring boot微服务。我已经使用spring安全性通过JWT样式令牌来保护它。一切正常,直到我使用RxJava io调度程序添加了线程池。我注意到当线程池与Spring Security一起使用时出现有线行为。当我保存数据时,会同时保存一个userId。当我以userOne登录后创建第一个对象时,将正确创建它。对于userTwo也是一样。然后说我以userThree身份登录并创建一个新数据,将其保存为userOne ID,这是错误的!仅当我在从池中获得的单独线程中执行操作时,此行为才会出现。
我的安全性配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public SecurityConfig(ApplicationProperties applicationProperties) { super(); this.applicationProperties = applicationProperties; SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); } @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.csrf().disable().headers().frameOptions().disable().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/api/**") .authenticated().antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) .antMatchers("/swagger-resources/configuration/ui").permitAll().antMatchers("/health/**").permitAll() .and() .addFilterAfter(new TokenAuthenticationProcessingFilter( new MyAuthenticationProvider(this.applicationProperties), "/api/**", null, new SimpleUrlAuthenticationFailureHandler()), BasicAuthenticationFilter.class); } |
为了简化和清楚起见,删除了不必要的代码。不仅对于RxJava,而且当
原因可能是此。安全上下文将继承到子线程。父线程从池中获取线程,然后向该线程提交任务。线程将继承安全上下文。任务完成后,线程将释放回池中。说当另一个请求到来时,先前使用的线程被重用。我怀疑安全上下文尚未删除,因此数据保存在旧用户的ID下。
这只是思维导图或想象力。那可能吗?如果是这样,解决该问题的解决方案是什么?有没有办法在线程释放回池之前清除安全上下文?
您是正确的,当重新使用池中的线程时,该线程中可能仍会存在任何线程本地数据。您正在尝试通过设置全局变量来使用安全证书,而该变量本质上是不安全的。 J2EE程序可以避免这种情况,因为线程模型很简单。
在跨多个线程可以进行事务的环境中,不能使用线程本地安全凭证。
一种可以与RxJava很好配合的方法是将凭据绑定到类上下文,并在该上下文中执行RxJava观察者链,以封闭凭据并确保引用的局部性。您为每个用户创建一个对象,将凭据绑定到该用户,然后在需要凭据的每个步骤中引用该用户的凭据。