想要实现网站同一账户在同一时间只能登录一次的功能,该如何实现? 如果保存用户信息是使用token并加载在缓存中,那么只需要在登录的接口中判断一步缓存中的用户是否与当前登录的用户相同就可以了。 但是如果系统框架是使用传统的session储存登录用户信息,该如何实现这个功能呢?
登录的时候request会带一个sessionId过去,这是每个单独的访问特有的(我理解的是每个浏览器相当于单独的会话,如果你在这个浏览器登录了,再开别的标签页系统也是会认为你已经登录过了,原因是sessionid是一致的),那么我们需要保存sessionid和当前登录的用户信息就可以实现了。
大体的思路是这样的:
- 在登录的接口中,用当前登录的userid去获取缓存中的sessionId,如果和当前访问的sessionId一致,那么放行。如果不一致,删除原缓存中的sessionId,换上新的sessionId。
- 在登录拦截器中,获取用户信息,(如果获取不到,跳转到登录页,这个是常规操作)通过用户信息(userid) 在缓存中获得sessionId,比较获取的sessionId和本次拦截的sessionId,如果不一致,拦截请求,提示用户账号被顶替了。
- 提示页跳转至登录页面(过一遍后台走一步登出流程)
存放登录信息的map
public class LoginUserData {
private static Map<String, String> sessionIDMap = new
HashMap<String,String>();
public static Map<String, String> getSessionIDMap() {
return sessionIDMap;
}
public static void setSessionIDMap(Map<String, String> sessionIDMap) {
LoginUserData.sessionIDMap = sessionIDMap;
}
}
在登录验证完成后,成功登录之后把用户信息和访问的sessionId存入上面的信息map中。
String sessionId = this.request.getRequestedSessionId();
String userId = tempUser.getId();
if (!LoginUserData.getSessionIDMap().containsKey(user)) { //不存在,首次登陆,放入
LoginUserData.getSessionIDMap().put(userId, sessionId);
}else if(LoginUserData.getSessionIDMap().containsKey(userId) && !sessionId.equals(LoginUserData.getSessionIDMap().get(userId))){
LoginUserData.getSessionIDMap().remove(userId);
LoginUserData.getSessionIDMap().put(userId, sessionId);
}
到这一步,登录成功的用户就可以在LoginUserData中获得了。但是要做到重复验证顶替或者禁止第二人登录的功能,需要在登陆拦截器中配置。每次登录请求从已经登录的用户中查询,如果sessionId不一致,则顶替。
String sessionid = LoginUserData.getSessionIDMap().get(user.getId());//如果用户名存在即登录放行)
if(sessionid.equals(request.getSession().getId())){
return true;
}else{
//如果请求的sessionID和此账号Map中存放的sessionID不一致,跳转到登陆页
//判断如果是异步请求,设置响应头 sessionstatus为timeout,自动跳转,否则重定向
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
response.setDateHeader("Expires",0);
response.sendRedirect(request.getContextPath() + "/***/***.jsp");
return false;
}
到这边就基本实现了不能重复登陆的问题。由于是通过sessionId来判断的,所以同一浏览器重复登录时,sessionId是一致的。不同浏览器登录则会顶替。BTW最好的办法还是使用token验证,但是我比较菜,有时间自己实现一次token验证登录的开发吧。目前都是用别人封装好的emmmmm