为了系统的安全性,很多网站都实现单用户登录,下面我们来探讨一下它的实现原理:
第一步:
public class SessionListener implements HttpSessionListener{
public static Map<Long, String> LOGIN_USER_MAP = new HashMap<Long, String>();//登入用户
public static Map<Long, String> LOGOUT_USER_MAP = new HashMap<Long, String>();//逼下线用户
//session创建
@Override
public void sessionCreated(HttpSessionEvent event) {
}
//session销毁
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
User user = (User) session.getAttribute(Common.LOGIN_USER);
if(user != null){
LOGIN_USER_MAP.remove(user.getEid());
}
}
}
创建session监听器,监听session的事件,同时我们创建两个Map,用来存储用户的ID和sessionId。
第二步:
//登录成功后
session.setAttribute(Common.LOGIN_USER, dbUser);
String sessionId = session.getId();
if(SessionListener.LOGIN_USER_MAP.containsKey(dbUser.getEid())){//存在用户
if(!sessionId.equalsIgnoreCase(SessionListener.LOGIN_USER_MAP.get(dbUser.getEid()))){//判断是否相同的sessionID
SessionListener.LOGOUT_USER_MAP.put(dbUser.getEid(), SessionListener.LOGIN_USER_MAP.get(dbUser.getEid()));
SessionListener.LOGIN_USER_MAP.put(dbUser.getEid(), sessionId);
}
}else{
SessionListener.LOGIN_USER_MAP.put(dbUser.getEid(), sessionId);
}
result = "redirect:/common/homepage/index.action";
登录成功后我们拿到登录后的用户ID,查找系统里该用户是否已经登录了,如果没有登录则保存到LOGIN_USER_MAP里,如果已经登录,则判断sessionID是否与之前登录的session相同,若不相同,需要把之前的session记录下来。
第三步:
public class LoginInterceptor implements HandlerInterceptor{
//返回值:表示我们是否需要将当前的请求拦截下来,返回false请求被拦截下来
//handler:表示被拦截请求的目标对象
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
User user = (User) session.getAttribute(Common.LOGIN_USER);
if(user == null){
response.sendRedirect(request.getContextPath() + "/common/login/index.action");
return false;
}
String sessionId = request.getSession().getId();
if(SessionListener.LOGOUT_USER_MAP.containsValue(sessionId)){//判断当前用户sessionID是否存在逼下线列表里
SessionListener.LOGOUT_USER_MAP.remove(user.getEid(), sessionId);
response.sendRedirect(request.getContextPath() + "/common/login/index.action?message=1");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//通过modelandview可以改变将要跳转的页面
}
//请求要结束的时候调用,主要是进行数据的销毁,流的关闭
//统一异常处理,统一日志处理
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
在登录拦截器里做判断,判断当前用户sessionID是否存在逼下线列表里,若存在,则拦截下来。
感兴趣的朋友可以关注微信公众号(会定时推送新的知识):