是 @Scheduled
注解方法中的任何 SecurityContext
? 当我尝试使用下面的内容时,它总是有 securitycontext/auth
为空。如果这是不可能的,那么有什么正确的方法来运行用户特定的认证意识的预定任务呢?
@Scheduled(fixedDelay = 10000)
// This method will send notifications to the current user
public void sendUserNotifications() {
SecurityContext sc = SecurityContextHolder.getContext();
Authentication auth = sc.getAuthentication();
if(auth == null) {
log.info(">> SecurityContext=[{}], Authentication[auth] is {}, please login to receive notifications", sc, auth);
return;
}
给定的摘录将永远不会工作。
解释。
原生会话管理由底层servlet API和容器提供。HttpSession
只有当用户使用以下方式登录时,才会创建一个对象 request.getSession()
引擎盖下 HttpSession
将由 SecurityContextHolder.getContext().getAuthentication();
内部。 这意味着它与用户的请求有关系,而用户的请求是一个容器管理的线程,而不是普通的JVM线程,你的调度器将在其上运行。
在这里,你的调度器对用户有任何依赖性,它将在JVM管理的线程上独立运行。所以没有 HttpRequest/HttpSession
对象将被创建。
想象一下,当你第一次启动应用程序时,还没有用户登录,那么这里会是什么情况。
所以,你总是会得到 securitycontext/auth
只作为空。
回答你的问题
如果这是不可能的,那么有什么正确的方法来运行用户特定的身份验证感知计划任务呢?
我现在能想到的一个方法是,使用spring提供的 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.
}
此外,你必须在你的安全配置中启用会话注册表,首先你必须监听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();
}
}
更多关于如何获得当前登录用户的详细信息 见此.
希望能帮到你