需求:使用者在 A 處登入後,若在 B 處再次登入,A 處應被強制下線。採用「後登入者踢除先登入者」策略。
Map<String, String> 保存 loginId -> sessionId,新登入直接覆蓋舊值。HttpSessionListener,在 Session 銷毀時移除 Map 中對應項目。Filter 攔截請求,驗證當前 Session ID 是否為 Map 中最新值,否則執行登出並導向登入頁提示。public class LoginUserMap {
private static Map<String, String> loginUsers = new ConcurrentHashMap<>();
public static void setLoginUsers(String loginId, String sessionId) {
loginUsers.put(loginId, sessionId);
}
public static Map<String, String> getLoginUsers() { return loginUsers; }
public static void removeUser(String sessionId) {
loginUsers.entrySet().removeIf(entry -> sessionId.equals(entry.getValue()));
}
public static boolean isInLoginUsers(String loginId, String sessionId) {
return loginUsers.containsKey(loginId) && sessionId.equals(loginUsers.get(loginId));
}
}
HttpSession session = request.getSession();
LoginUserMap.setLoginUsers(username, session.getId());
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
LoginUserMap.removeUser(event.getSession().getId());
}
}
@WebFilter(urlPatterns = "/*")
public class LoginLimitFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session != null) {
IUser user = UserUtils.getCurrUserInfo(); // 專案自有工具類
if (user != null) {
String loginId = user.getLoginId();
if (!LoginUserMap.isInLoginUsers(loginId, session.getId())) {
// 被踢下線處理
logout(); // 自有登出邏輯
response.sendRedirect(request.getContextPath() + "?logoutway=edge");
return;
}
}
}
chain.doFilter(req, res);
}
}
window.onload = function() {
if (GetQueryString('logoutway')) {
layer.alert('該賬號已在其他地方登錄,您已被迫下線...', {
skin: 'layui-layer-lan', title: '提示', closeBtn: 0
}, function() {
var url = window.location.href;
window.location.href = url.substr(0, url.indexOf('?logoutway=edge'));
});
}
}