Spring mvc shiro 同一账号多人同时登陆强制下线

创建logout.Java用来记录当前在线的用户

@SuppressWarnings(value = "ALL")
public final class Logout implements Runnable {

    private static final HashMap MAP = new HashMap<>();

    /**
     * 在登陆时将已登录的用户信息放入map中
     *
     * @param userId   用户id
     * @param loginLog 用户信息
     */
    public static void putUserLoginLog(String userId, LoginLog loginLog) {
        MAP.put(userId, loginLog);
    }

    /**
     * 通过用户id得到用户信息
     *
     * @param userId
     * @return
     */
    public static LoginLog getLoginLog(String userId) {
        return MAP.get(userId);
    }

    /**
     * 通过用户信息更新用户最后操作时间
     *
     * @param userId
     */
    public static void updateLoginLastTime(String userId) {
        MAP.get(userId).setLastTime(System.currentTimeMillis());
    }

    /**
     * 每30分钟检测一次map中的用户是否长时间不在线,防止用户不在线和还存在map中占用内存
     */

    @Override
    public void run() {
        while (true) {
            for (String userid : MAP.keySet()) {
                if (System.currentTimeMillis() - MAP.get(userid).getLastTime() > 30 * 60 * 1000) {
                    MAP.remove(userid);
                }
            }
            try {
                Thread.sleep(30 * 60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

创建拦截器类实现HandlerInterceptor

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object
            o) throws Exception {
        return true;
    }

    /**
     * 通过shiro方法获取当前用户,
     * 如果当前用户为空,表示第一次登陆,则可以继续执行,
     * 否则通过用户id得到当前用户登陆信息,
     * 如果没有获取到登陆信息,继续执行,
     * 判断用户的sessionId是否相同并且用户最后登陆时间是否小于30分钟
     * 如果成立则在shiro中退出登陆同时重定向到登陆页
     *
     * @param request
     * @param response
     * @param o
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o,
                           ModelAndView modelAndView) throws Exception {
        //
        LoginUser loginUser = CommonUtil.getLoginUser();
        if (loginUser != null) {
            String sessionId = request.getSession().getId();
            String personId = loginUser.getPersonId();
            LoginLog loginLog = Logout.getLoginLog(personId);
            if (loginLog != null) {
                long time = (System.currentTimeMillis() - loginLog.getLastTime()) / 1000 / 60 / 30;
                if (!sessionId.equals(loginLog.getSessionId()) && time < 30) {
                    SecurityUtils.getSubject().logout();
                    response.sendRedirect(request.getContextPath() + "/index");
                } else {
                    Logout.updateLoginLastTime(personId);
                }
            }
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e)
            throws Exception {

    }
}

创建监听器实现ApplicationContextAware

/**
 * 在项目启动时开启用户登陆信息扫描的线程
 */
@Component
public class LogoutListener implements ApplicationContextAware {

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Thread thread = new Thread(new Logout());
        thread.start();
    }

}

你可能感兴趣的:(杂记)