zoukankan      html  css  js  c++  java
  • java web 限制同一个用户在不同处登入

    用到的技术:map集合,sessionListener监听器,Fiter过滤器。

    实现思路:

      一.利用一个全局的map集合来保存每个用户sessionID的值的一个集合。一个用户对应一个sessionID当相同的用户登录的时候判断它在集合总有没有值。(保存用户所有登录记录)

      二.

        2.1.实现sessionListener在当一个session被销毁的时候强制移除当前用户所对应的sessionID

        2.2.实现Fiter来判断每次请求map集合中是否有值。(实现强制退出)

    代码:代码是复制别人的,做了些修改。

    public class LoginUserMap {
      //ConcurrentHashMap这个集合是线程安全的而且性能方面比hasTable和hasMap都好。在高并发的条件下执行速度更快。
      private static Map<String, String> loginUsers = new ConcurrentHashMap<String, String>();
     
      /**
       * 将用户和sessionId存入map
       * @param key
       * @param value
       */
      public static void setLoginUsers(String loginId, String sessionId) {
        loginUsers.put(loginId, sessionId);
      }
     
      /**
       * 获取loginUsers
       * @return
       */
      public static Map<String, String> getLoginUsers() {
        return loginUsers;
      }
     
      /**
       * 根据sessionId移除map中的值
       * @param sessionId
       */
      public static void removeUser(String sessionId) {
        for (Map.Entry<String, String> entry : loginUsers.entrySet()) {
          if (sessionId.equals(entry.getValue())) {
            loginUsers.remove(entry.getKey());
            break;
          }
        }
      }
     
      /**
       * 判断用户是否在loginusers中
       * @param loginId
       * @param sessionId
       * @return
       */
      public static boolean isInLoginUsers(String loginId, String sessionId) {
        return (loginUsers.containsKey(loginId) && sessionId.equals(loginUsers.get(loginId)));
      }
     
    }
    //登录方法所在的地方
    public void login(ttpServletRequest request) {
      try
          ......//一系列登录的方法
          HttpSession session = request.getSession();
          LoginUserMap.setLoginUsers(username, session.getId());//保存sessionId到map中
        } catch (LoginException ex) {
          throw ex;
        }
    }
    //实现HttpSessionListener
    public class SessionListener implements HttpSessionListener {
      private Log log = LogFactory.getLog(SessionListener.class);
     
      /**
       * 创建session时候的动作
       * @param event
       */
      @Override
      public void sessionCreated(HttpSessionEvent event) {
     
      }
     
      /**
       * 销毁session时候的动作
       * @param event
       */
      @Override
      public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        String sessionId = session.getId();
        //移除loginUsers中已经被销毁的session
        LoginUserMap.removeUser(sessionId);
        log.info(sessionId + "被销毁!");
        }
    }
    //xml配置
    <listener>
      <listener-class>....SessionListener</listener-class>
    </listener>
    //实现过滤器
    public class LoginLimitFilter implements Filter{
     
      private Log log = LogFactory.getLog(LoginLimitFilter.class);
     
      /**
       * 销毁时的方法
       */
      @Override
      public void destroy() {
     
      }
     
      /**
       * 过滤请求
       * @param request
       * @param response
       * @param filterChain
       * @throws IOException
       * @throws ServletException
       */
      @Override
      public void doFilter(ServletRequest request, ServletResponse response,
         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        HttpServletResponse servletResponse = (HttpServletResponse) response;
        HttpSession session = servletRequest.getSession();
     
        //获取项目路径
        String path = servletRequest.getContextPath();
        String basePath = servletRequest.getScheme()+"://"+servletRequest.getServerName()+":"+servletRequest.getServerPort()+path;
     
        try {
          //获取登录信息
          String loginId = session.getAttribute("yhid")
          //判断当前用户的sessionId是否在loginUsers中,如果没有执行if后的操作
          if(!LoginUserMap.isInLoginUsers(loginId, session.getId())) {
            //当前用户logout 注:退出登录最好别用session销毁的方法。
            logout();//自己的logout方法
            //调到登录页面,并表明退出方式为挤下线
            servletResponse.sendRedirect(basePath + "?logoutway=edge");
          }
        } catch (Exception e) {
          log.debug("获取当前用户信息失败,用户未登陆!", e);
        } finally {
          filterChain.doFilter(request, response);
        }
      }
     
      /**
       * 初始化方法
       * @param arg0
       * @throws ServletException
       */
      @Override
      public void init(FilterConfig arg0) throws ServletException {
     
      }
     
    }
    //xml
    <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>
    //前台页面js放在首页就可以了
    window.onload = function(){
      if(window.parent != window){
        window.parent.location.href=window.location.href;
      } else {
        if(GetQueryString('logoutway')) {
          alert('该用户已在其他地方登录,你已下线');     
          var url = window.location.href;
          window.location.href = url.substr(0,url.indexOf('?logoutway=edge'));
       }
      }
    }
     
    function GetQueryString(name)
    {
       var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
       var r = window.location.search.substr(1).match(reg);
       if(r!=null)return unescape(r[2]); return null;
    }
     
    原文链接:http://www.jianshu.com/p/24bc2bb1444e#
  • 相关阅读:
    C++ 4种强制类型转换
    HTTP与HTTPS异同/HTTP1.0与HTTP1.1差别
    大数据处理-Trie树
    Linux进程状态转换图
    纯css实现背景图片半透明内容不透明的方法-opacity属性正确使用
    由vue理解passive修饰符引起的思考
    Vue+VSCode开发环境配置备忘(代码格式设置)
    哎呦喂web 前端三日老师 《精通Flex布局》
    flex实战之移动页面确定按钮置底布局
    Poptip插件拖动造成IOS下与同页面下mescroll.js也被拖动的解决,即对e.preventDefault();的理解
  • 原文地址:https://www.cnblogs.com/lmq3321/p/7233096.html
Copyright © 2011-2022 走看看