首先确保springSecurity的版本是2.7.9
第一步:配置filterChain()方法
java
.and()
.sessionManagement()
// 设置一个session最多只能有一个用户使用,默认是无限制
.maximumSessions(1)
.sessionRegistry(sessionRegistry)
.expiredSessionStrategy(sessionInformationExpiredStrategy);
.maximumSessions(1): 设置一个会话最多只能有一个用户使用。这意味着当一个用户已经登录并且会话尚未过期时,如果另一个用户尝试使用相同的凭据登录,先前的会话将被失效。
.sessionRegistry(sessionRegistry): 设置一个用于跟踪活动会话的SessionRegistry对象。SessionRegistry用于管理和访问当前活动会话的信息。
java
@Resource
private SessionRegistry sessionRegistry;
.expiredSessionStrategy(sessionInformationExpiredStrategy): 设置一个会话过期策略。当会话过期时,将采取特定的操作。sessionInformationExpiredStrategy是一个实现了SessionInformationExpiredStrategy接口的自定义策略对象,用于定义会话过期后的处理逻辑。
通过以上配置,可以实现对会话的最大并发控制和会话过期处理.
第二步:重写SessionInformationExpiredStrategy中的onExpiredSessionDetected方法,自定义会话过期策略
java
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
private static final Logger logger = LogManager.getLogger(MySessionInformationExpiredStrategy.class);
@Resource
AuthenticationFailureHandlerImp authenticationFailureHandlerImp;
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) {
// 1. 获取用户名
UserDetails userDetails = (UserDetails) event.getSessionInformation().getPrincipal();
AuthenticationException exception = new AuthenticationServiceException(
String.format("[%s]用户在另外一台电脑登录,您已被下线", userDetails.getUsername()));
try {
// 当用户在另外一台电脑登录后,交给失败处理器回到认证页面
event.getRequest().setAttribute("toAuthentication" , true);
authenticationFailureHandlerImp.onAuthenticationFailure(event.getRequest(),event.getResponse(),exception);
}catch (Exception e){
logger.error("MySessionInformationExpiredStrategy->onExpiredSessionDetected:{}", e.getMessage());
}
}
}
第三步:把SessionRegistry和SessionInformationExpiredStrategy注册到springboot中交由springboot管理
java
@Configuration
public class Config {
@Bean
@ConditionalOnMissingBean(SessionInformationExpiredStrategy.class)
public SessionInformationExpiredStrategy informationExpiredStrategy() {
return new MySessionInformationExpiredStrategy();
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
第四步:在AuthenticationFailureHandler方法定义一下,springSecurity的登录失败回调方法
我是这样写的,比较粗糙
java
@Component
public class AuthenticationFailureHandlerImp implements AuthenticationFailureHandler {
private static final Logger logger = LogManager.getLogger(AuthenticationFailureHandlerImp.class);
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response
, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
if (exception.getMessage().indexOf("您已被下线") !=0) {
response.setStatus(400);
response.getWriter().append(ResponseStatus.createFailureStatus(exception.getMessage()).toString());
}else {
response.setStatus(403);
response.getWriter().append(ResponseStatus.createFailureStatus("登录失败").toString());
}
logger.error("AuthenticationFailureHandlerImp: {}", exception.getMessage());
}
}
结束:
A用户在A电脑上登录,之后A用户又在B电脑上登录,这个时候,A电脑在去访问我们的后端接口就会提示"A用户在另外一台电脑登录,您已被下线",还没有做到实时通知,感兴趣的可以自己实现一下