鉴于摘录永远不会奏效。
解释:
本机会话管理由底层 servlet API 和容器提供。HttpSession
仅当用户在后台使用登录时才创建对象request.getSession()
,稍后HttpSession
将由SecurityContextHolder.getContext().getAuthentication();
内部使用。这意味着它与用户的请求有关,这是一个容器管理的线程,而不是调度程序将在其上运行的普通旧 JVM 线程。
在这里,您的调度程序确实对用户有任何依赖关系,它将在 JVM 托管线程上独立运行。所以根本HttpRequest/HttpSession
不会创建任何对象。
想象一下,当您第一次启动应用程序并且还没有用户登录时,这里会发生什么情况。
因此,您将始终securitycontext/auth
仅获得 null 。
回答你的问题
如果这是不可能的,那么运行用户特定身份验证感知计划任务的正确方法是什么?
我现在能想到的一种方法是,使用提供的弹簧SessionRegistry
。它跟踪所有当前登录的用户。
因此,您可以通过SessionRegistry
自动装配将此对象传递给此调度程序,并获取所有主体/登录用户的列表并向他们发送通知。
像下面的东西 -
@EnableScheduling
@Component
public class MyScheduler {
@Autowired
@Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;
@Scheduled(fixedDelay = 10000)
// This method will send notifications to the current user
public void sendUserNotifications() {
List<UserDetails> principals = sessionRegistry.getAllPrincipals()
.stream()
.filter(principal -> principal instanceof UserDetails)
.map(UserDetails.class::cast)
.collect(Collectors.toList());
// send notification to all users.
}
此外,您必须首先在安全配置中启用 sessionRegistry,您必须先侦听 HTTP 会话,然后在安全配置中配置注册表。
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
...
servletContext.addListener(HttpSessionEventPublisher.class);
}
}
和安全配置 -
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
// ...
http.sessionManagement().maxSession(1).sessionRegistry(sessionRegistry());
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
有关如何获取当前登录用户的更多详细信息,请参见此处。