NullPointerException在过期的会话上

时间:2019-07-18 18:43:29

标签: java spring security session model-view-controller

我正在使用Spring,更新该用户时需要终止该用户的会话。我正在使用以下配置:

@Bean
@Override
public AuthenticationManager authenticationManagerBean () throws Exception {

    return super.authenticationManagerBean();

}

@Bean
public SessionRegistry sessionRegistry () {

    return new SessionRegistryImpl();

}
@Bean
public ServletListenerRegistrationBean httpSessionEventPublisher() {    //(5)
    return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
}

@Override
public void configure(AuthenticationManagerBuilder authenticationMgr) throws Exception {

    authenticationMgr.userDetailsService(inMemoryUserDetailsManager());

}

@Override
protected void configure (HttpSecurity http) throws Exception {

    http.authorizeRequests()
        .antMatchers("*.jsp").authenticated()
        .and()
            .formLogin().loginPage("/login.html")
            .defaultSuccessUrl("/")
            .failureUrl("/login.html?failed=1")
            .usernameParameter("email").passwordParameter("password")               
        .and()
            .logout().logoutUrl("/logout.html")
        .and()
            .logout().logoutSuccessUrl("/")
        .and()
            .sessionManagement()
            .maximumSessions(100)
            .maxSessionsPreventsLogin(true)
            .expiredUrl("/ejercicios-programacion/")
            .sessionRegistry(sessionRegistry());

}

这是我终止会话的方式:

public void expireUserSessions(String username) {
    for (Object principal : sessionRegistry.getAllPrincipals()) {
        if (principal instanceof User) {
            UserDetails userDetails = (UserDetails) principal;
            if (userDetails.getUsername().equals(username)) {
                for (SessionInformation information : sessionRegistry.getAllSessions(userDetails, false)) {
                    information.expireNow();
                }
            }
        }
    }
}

完成此操作后,当我在浏览器中重新加载更新用户的页面时,它将显示异常:

java.lang.NullPointerException
org.springframework.security.web.session.ConcurrentSessionFilter$1.onExpiredSessionDetected(ConcurrentSessionFilter.java:107)

哪个重定向到:

@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
    HttpServletRequest request = event.getRequest();
    HttpServletResponse response = event.getResponse();
    SessionInformation info = event.getSessionInformation();

    redirectStrategy.sendRedirect(request, response, determineExpiredUrl(request, info));
}

特别是,这是引发异常的最后一行代码。如果我在得到异常后再次重新加载页面,那么一切都很好。我没有例外,我已经注销。我不知道为什么会这样。有人知道吗?

1 个答案:

答案 0 :(得分:0)

好的,我终于设法解决了这个问题。答案是使用您自己的ConcurrentSessionFilter,因为不赞成使用默认方法中的许多方法。添加此豆:

 @Bean public ConcurrentSessionFilter concurrentSessionFilter() {

    ConcurrentSessionFilter c = new ConcurrentSessionFilter(sessionRegistry(), new SessionInformationExpiredStrategy() {

        @Override
        public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {

            HttpServletRequest request = event.getRequest();
            HttpServletResponse response = event.getResponse();
            SessionInformation info = event.getSessionInformation();

            redirectStrategy().sendRedirect(request, response, "/ejercicios-programacion/");

        }
    });

    return c;

}

在覆盖的方法中做任何您想做的事情,在我的情况下,我使用新的RedirectStrategy将用户移动到索引页面。

然后将其添加到您的配置方法中:

protected void configure (HttpSecurity http) throws Exception {

    ...
    // Whatever you want to configure

    http.addFilterBefore(concurrentSessionFilter(), ConcurrentSessionFilter.class);

}

我简直不敢相信这是多么不直观,我不知道到期会话这样简单的事情在Spring会变得如此艰难和令人困惑