3

@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;
        }
4

1 回答 1

0

鉴于摘录永远不会奏效。

解释:

本机会话管理由底层 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();
    }
 }

有关如何获取当前登录用户的更多详细信息,请参见此处

于 2020-05-30T07:54:25.333 回答