我有一个事件监听器,当它收到用户更改密码的事件时会使会话无效。这是代码:
@Component
public class UserListener {
private static Logger logger = LoggerFactory.getLogger(UserListener.class);
@Autowired
private SessionRegistry sessionRegistry;
@EventListener
public void handleChangePasswordEvent(ChangePasswordEvent event) {
logger.info("handleChangePasswordEvent for : " + event.getUsername());
List<Object> loggedUsers = sessionRegistry.getAllPrincipals();
logger.info("loggedUsers : " + loggedUsers.size());
for (Object principal : loggedUsers) {
if (principal instanceof User) {
final User loggedUser = (User) principal;
logger.info("loggedUser : " + loggedUser.getUsername());
if (event.getUsername().equals(loggedUser.getUsername())) {
List<SessionInformation> sessionsInfo = sessionRegistry.getAllSessions(principal, false);
if (null != sessionsInfo && sessionsInfo.size() > 0) {
for (SessionInformation sessionInformation : sessionsInfo) {
logger.info("Exprire now :" + sessionInformation.getSessionId());
sessionInformation.expireNow();
sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
// User is not forced to re-logging
}
}
}
}
}
}
}
监听器工作正常,问题是返回sessionRegistry的经过身份验证的用户列表为空。
我已经尝试了所有我遇到的同样问题的解决方案,但他们没有为我工作。
这里我放了Spring Security的所有配置。
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableWebSecurity
@ComponentScan(value = { "security" })
public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private CustomLogoutHandler logoutHandler;
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationEventPublisher(authenticationEventPublisher())
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
return new DefaultAuthenticationEventPublisher();
}
/**
* Security Configuration for Admin zone
*/
@Configuration
@Order(1)
public class AdminConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationSuccessHandler successHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**")
.hasAuthority(AuthorityEnum.ROLE_ADMIN.name())
.and()
.formLogin()
.loginPage("/admin/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(successHandler)
.permitAll()
.and()
.logout()
.addLogoutHandler(logoutHandler)
.logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
.logoutSuccessUrl("/admin/login?logout")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf()
.disable();
}
}
/**
* Security Configuration for Frontend zone
*/
@Configuration
@Order(2)
public class FrontendConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/*.*")
.permitAll()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.addLogoutHandler(logoutHandler)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf();
}
}
@Configuration
@Order(3)
public class GlobalWebConfiguration extends WebSecurityConfigurerAdapter {
private SessionRegistry sessionRegistry;
@Autowired
private MessageSource messageSource;
@Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionAuthenticationStrategy(compositeSessionAuthenticationStrategy())
.sessionFixation()
.changeSessionId()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.expiredUrl("/login?expired")
.sessionRegistry(sessionRegistry())
.and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
// Here we protect site from:
// 1. X-Content-Type-Options
http.headers().contentTypeOptions();
// 2. Web Browser XSS Protection
http.headers().xssProtection();
http.headers().cacheControl();
http.headers().httpStrictTransportSecurity();
// 3. X-Frame-Options
http.headers().frameOptions();
}
@Bean
public SessionRegistry sessionRegistry() {
if (sessionRegistry == null) {
sessionRegistry = new SessionRegistryImpl();
}
return sessionRegistry;
}
@Bean
@Order(1)
public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy() {
ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
strategy.setExceptionIfMaximumExceeded(true);
strategy.setMessageSource(messageSource);
return strategy;
}
@Bean
@Order(2)
public SessionFixationProtectionStrategy sessionFixationProtectionStrategy(){
return new SessionFixationProtectionStrategy();
}
@Bean
@Order(3)
public RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy(){
RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy = new RegisterSessionAuthenticationStrategy(sessionRegistry());
return registerSessionAuthenticationStrategy;
}
@Bean
public CompositeSessionAuthenticationStrategy compositeSessionAuthenticationStrategy(){
List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();
sessionAuthenticationStrategies.add(concurrentSessionControlAuthenticationStrategy());
sessionAuthenticationStrategies.add(sessionFixationProtectionStrategy());
sessionAuthenticationStrategies.add(registerSessionAuthenticationStrategy());
CompositeSessionAuthenticationStrategy compositeSessionAuthenticationStrategy = new CompositeSessionAuthenticationStrategy(sessionAuthenticationStrategies);
return compositeSessionAuthenticationStrategy;
}
}
}
我有一个用于管理区域的WebSecurityConfigurerAdapter,它有自己的登录页面,另一个用于普通用户。
最后是 GlobalWebConfiguration ,为两个区域(管理员和用户)配置会话管理器。
希望有人可以帮助我