Given excerpt will never work.
Explanation:
Native session management is provided by underlying servlet API and container. HttpSession
object is only created when the user logs in using request.getSession()
under the hood and later this HttpSession
will be used by SecurityContextHolder.getContext().getAuthentication();
internally. This means it has a relation with the user's request which is a container-managed thread, not plain old JVM thread on which your scheduler will run.
Here your scheduler does not have any dependency on the user it will run independently on JVM managed thread. So no HttpRequest/HttpSession
object will be created at all.
Imagine the very first time when you start the application and no user yet logged in then what would be scenario here.
So you will always get securitycontext/auth
as null only.
To answer your question
If this is not possible then what could be the right way to run user
specific authentication aware scheduled task?
One way I can think of right now is, Use of spring provided SessionRegistry
.
It keeps track of all currently logged-in users.
So you can pass this SessionRegistry
object by autowiring to this scheduler and get list of all principal/logged-in users and send them a notification.
Something like below -
@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.
}
Also, you have to enable sessionRegistry in your security config first you have to listen to HTTP sessions and then configure registry in your security config.
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
...
servletContext.addListener(HttpSessionEventPublisher.class);
}
}
and security config -
@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();
}
}
For more details of how to get current logged in users see here.