在我的网络应用程序中,我需要知道用户是在线还是离线。我需要在创建或销毁用户会话时更新数据库中的状态,因此SessionRegistry不是一个选项。
我使用会话计数器实现它 - 当用户登录时,他的计数器递增,当他退出或他的会话超时时,他的计数器减少。
的web.xml
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
服务
@Service
public class UsersLoginLogoutListener implements ApplicationListener<ApplicationEvent> {
@Autowired
private AccountService accountService;
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof InteractiveAuthenticationSuccessEvent) { // User log in
System.out.println("User logged in...");
InteractiveAuthenticationSuccessEvent iasEvent = (InteractiveAuthenticationSuccessEvent) event;
String userName = iasEvent.getAuthentication().getName();
if (userName != null) {
System.out.println("...username is " + userName + ".");
accountService.incrementSessionCounter(userName);
}
}
else if (event instanceof SessionDestroyedEvent) { // User log out / session timeout
System.out.println("User logged out or session timeout...");
SessionDestroyedEvent sdEvent = (SessionDestroyedEvent) event;
List<SecurityContext> lstSecurityContext = sdEvent.getSecurityContexts();
System.out.println("...SecurityContexts list size: " + lstSecurityContext.size() + "...");
for (SecurityContext securityContext : lstSecurityContext)
{
String userName = securityContext.getAuthentication().getName();
if (userName != null) {
System.out.println("...username is " + userName + ".");
accountService.decrementSessionCounter(userName);
}
}
}
}
}
直到最近,当我注意到一个计数器增加但从未减少时,它一直工作得很好。感谢日志,我能够重现它。
用户在两个浏览器选项卡中打开登录页面并在一个选项卡上登录,然后他登录另一个选项卡而不登出第一个选项卡。如果他输入了正确的凭证,一切正常:
用户登录... ...用户名是testuser。
用户注销或会话超时...... ... SecurityContexts列表大小: 1 ......用户名是testuser。
用户登录... ...用户名是testuser。
即使他使用相同的浏览器登录两次,他的第一个会话也被销毁,我的计数器正常工作。 但如果他输入了错误的凭据,我会看到以下输出:
用户登录... ...用户名是testuser。
(会话超时后)
用户注销或会话超时...... ... SecurityContexts列表大小: 0 ...
正如您所看到的,在这种情况下,SessionDestroyedEvent被触发,但仅在会话超时和SecurityContexts列表为空之后,因此用户的会话计数器未递减。