我使用@Async异步调用Spring方法.该方法调用其他使用@PreAuthorize,Spring Security Annotation注释的方法.要使授权工作,我必须将SecurityContextHolder模式设置为MODE_INHERITABLETHREADLOCAL,以便将身份验证信息传递给异步调用.到目前为止一切正常.
但是,当我以不同的用户身份注销和登录时,在异步方法中,SecurityContextHolder会存储已注销的旧用户的身份验证信息.它当然会引起不必要的AccessDenied异常.同步调用没有这样的问题.
我已定义<task:executor id="executors" pool-size="10"/>,所以可能是一个问题,一旦执行程序池中的线程已初始化,它将不会覆盖身份验证信息?
我在我的服务中使用异步方法(Spring 3 @Async注释).而且我遇到了问题 - 衍生线程没有安全上下文.原因是Spring Security默认使用SecurityContextHolder.MODE_THREADLOCAL其上下文持有者的策略.但我需要使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL策略.目前我在AuthenticationSuccessHandler中设置了策略.但在我看来,这不是一个好习惯.
那么如何在上下文配置文件中进行设置呢?
spring security的版本是3.0.0.
我创建了一个需要使用 JWT 进行身份验证的 REST API。
我的实现与https://auth0.com/blog/securing-spring-boot-with-jwts/上的代码非常相似
当我尝试返回当前用户时,我总是收到null返回。
我的代码:
网络安全:
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
// login
.antMatchers(HttpMethod.POST, "/login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(new JWTLoginFilter(
"/login", authenticationManager(), logService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
Run Code Online (Sandbox Code Playgroud)
JWTAuthenticationFilter:
public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest)req);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(req, res);
}
}
Run Code Online (Sandbox Code Playgroud)
我没有包含 JWT …
目前,我的AuditorAware实现使用 SpringSecurityContextHolder来检索当前 Auditor 以保存创建/修改用户名:
@Service
public class AuditorAwareImpl implements AuditorAware<UserDetails> {
private final UserDetailsService userDetailsService;
@Autowired
public AuditorAwareImpl(UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
}
@Override
public UserDetails getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return userDetailsService.loadUserByUsername(authentication.getName());
}
}
Run Code Online (Sandbox Code Playgroud)
除了 Spring 批处理执行的异步任务之外,这对于大多数操作都适用SimpleAsyncTaskExecutor。
当实体需要保存时,由于在SecurityContextHolder处理请求后被擦除,并且jobLauncher.run(...)异步返回,该方法会因 null 而AuditorAwareImpl.getCurrentAuditor()抛出a :NullPointerExceptiongetAuthentication()
java.lang.NullPointerException: null
at com.example.services.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:31)
at com.example.services.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:18)
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已将请求调用用户作为非标识参数包含到作业中,但不知道从这里继续进行。
SecurityContextHolder当不适合查找调用的“审计员”时,利用 Spring 内置审计的推荐方法是什么?