实现思路是依赖于spring-security中的sessionRegistry和SessionInformation两个对象来判断和删除session。
UsernamePasswordAuthenticationFilter 实现类的attemptAuthentication方法中实现主要判断和删除session的逻辑:
//获取所有在线用户
List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
allPrincipals.stream().forEach(o -> {
String username1 = (String) o;
//遍历根据用户名判断是否包含当前登录用户
if (username1.equals(jsonUsername)){
//获取所有在线用户的session
SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
List<SessionInformation> allSessions;
if (null != sc) {
allSessions = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false);
} else {
StrUserDetails strUserDetails = new StrUserDetails();
strUserDetails.setUsername(jsonUsername);
strUserDetails.setPassword(jsonPassword);
allSessions = sessionRegistry.getAllSessions(strUserDetails, false);
}
//如果同一账号在多个客户端登陆,则剔除第一个用户
for (SessionInformation allSession : allSessions) {
if (!allSession.getSessionId().equals(request.getSession().getId())) {
SessionInformation sessionInformation = sessionRegistry.getSessionInformation(allSession.getSessionId());
sessionInformation.expireNow();
}
}
}
});
//用户名密码验证通过后,注册session
sessionRegistry.registerNewSession(request.getSession().getId(), authRequest.getPrincipal());
这样前一个用户的session就直接超时了,无法进行数据操作,所以在
WebSecurityConfigurerAdapter实现类的configure方法中需要指定一个session超时的controller:
//session回话超时调用controller
.and().sessionManagement().invalidSessionUrl("/auth/timeout")