在网上有很多解决限制登录的方法,包括SpringSecurity也有解决的方案,今天记录一下使用JavaWeb的实现
知识点
思路如下:
演示
具体实现:
1.维护一个map集合
public class LoginUserMap {
private static Map<String, String> loginUserMap = new ConcurrentHashMap<String, String>();
/**
* set方法
*
* @param loginId 用户唯一标识,用户名或者用户Id
* @param sessionId sessionId
*/
public static void setLoginUserMap(String loginId, String sessionId) {
loginUserMap.put(loginId, sessionId);
}
/**
* get方法
*
* @return
*/
public static Map<String, String> getLoginUserMap() {
return loginUserMap;
}
/**
* 根据sessionId移除map中的值
*
* @param sessionId
*/
public static void removeUser(String sessionId) {
for (Map.Entry<String, String> entry : loginUserMap.entrySet()) {
if (sessionId.equals(entry.getValue())) {
loginUserMap.remove(entry.getKey());
break;
}
}
}
/**
* 判断用户是否在map中
*
* @param loginId
* @param sessionId
* @return
*/
public static boolean isInLoginUsers(String loginId, String sessionId) {
return (loginUserMap.containsKey(loginId) && sessionId.equals(loginUserMap.get(loginId)));
}
2.实现一个session监听,session销毁能及时更新map
@WebListener
public class SessionListener implements HttpSessionListener {
private Logger logger=LoggerFactory.getLogger(SessionListener.class);
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
HttpSession session = httpSessionEvent.getSession();
String sessionId = session.getId();
//session销毁时消除loginUserMap中的sessionId
LoginUserMap.removeUser(sessionId);
logger.info("session销毁,sessionId:"+sessionId);
}
}
3.定义过滤器,可自定义一个过滤器,但要排除登录请求(略),核心代码如下
//判断是否重复登录
String loginName = username.getLoginName();//获取用户唯一标识
//判断当前用户session是否改变
if (!LoginUserMap.isInLoginUsers(loginName,session.getId())) {
//定义自己的实现方式,被挤下线,我的是:
//session发送改变,表示别处登录
//被挤下线,清除session,提示信息,实现跳转
request.setAttribute("online",false);
request.getRequestDispatcher("/logout.do").forward(request,response);
return;
}
chain.doFilter(new XssHttpSerlet((HttpServletRequest) request), response);
4.注册监听和过滤器
<filter>
<filter-name>LoginLimitFilter</filter-name>
<filter-class>io.github.brightloong.loginlimite.LoginLimitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginLimitFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
另外,可以设置轮询的方式判断,让用户及时下线,但消耗资源,我采取的是请求失败跳转的方式,直接调用退出登录的接口
总结
实现无法解决同一浏览器多次登录的问题,及sessionId相同,但能实现基本的限制登录的操作,因为做的是踢线下,所以相比账号在线,无法登录来说,稍微简单,若做第二种形式,则需要考虑session是否消除的问题
//原文:https://brightloong.github.io/2017/03/08/Java-Web%E4%B9%8B%E9%99%90%E5%88%B6%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E5%A4%9A%E5%A4%84%E7%99%BB%E5%BD%95/#more