多用户登录限制

参考:java web项目防止多用户重复登录解决方案

最近闲来没事,但就这么闲着心里老不踏实,总得找点事干干啊,大好时光不能白白浪费啊,于是乎捋了捋平时工作会遇到的一些常见问题,首先想到了多用户登录限制问题,下面就对此问题做一点思考讲解。

1、设计场景

  1)同一时刻不允许某个用户多地登录

  2)用户已在A处登录,现在从B处登录是允许的,但会把A处挤掉(考虑到用户在A处登录后因某些情况跑到了B处,但还想继续之前的工作,所以需要登录系统)

  3)B处挤掉A后,A再做其它操作的时候系统会给出提示,该用户在别处登录,如不是本人操作可能密码泄漏,请修改密码。

2、思路导图

  每个用户登录的时候,通常我们会将用户信息存入session,以便用户进行操作的时候系统方便得到用户的基本信息。但这个session具有私有性,只对当前用户可见(如果同意用户在不同浏览器登录会得到不同的session,这也是为什么可以多用户登录的根源所在)。那么接着问题就来了,某个用户登录的时候如何能知道自己是否在线,相信聪明的你已经想到,这还不好半,把在线的用户信息存储在一个公共的地方问题不就迎刃而解了么,网上一查,解决方案无出其右,大致为以下两种

  1)数据库中标识在线用户

  2)存储到application中

  经过重重考虑,我们会发现方案一需要解决许多棘手的问题(用户异常退出未来得及修改状态,频繁访问数据库影响性能等),这对于一个要求完美的你来说显然是不合时宜的,于是我们采用了方案二,将在线用户信息保存到application中,具体设计如下。

  1)登录流程图

  

  2)被挤掉后操作流程图

  

3、代码

  1)登录判断是否已经在线

  

@Service
@Transactional
public class LimiteLogin {

    private static Logger log = Logger.getLogger(SessionListener.class);

    private static Map<String, String> loginUserMap = new HashMap<>();//存储在线用户
    private static Map<String, String> loginOutTime = new HashMap<>();//存储剔除用户时间
    @Autowired
    private UserService userService;

    public String loginLimite(HttpServletRequest request, String userName) {
        User user = userService.findByUserName(userName);
        String sessionId = request.getSession().getId();
        for (String key : loginUserMap.keySet()) {
            //用户已在另一处登录
            if (key.equals(user.getUserName()) && !loginUserMap.containsValue(sessionId)) {
                log.info("用户:" + user.getUserName() + ",于" + DateUtil.dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "被剔除!");
                loginOutTime.put(user.getUserName(), DateUtil.dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss"));
                loginUserMap.remove(user.getUserName());
                break;
            }
        }

        loginUserMap.put(user.getUserName(), sessionId);
        request.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);
        request.getSession().getServletContext().setAttribute("loginOutTime", loginOutTime);
        return "success";
    }

}

  2)登录拦截器(未登录跳转登录页)

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("now_user");
        if (session.getAttribute("now_user") == null) {
            response.sendRedirect(request.getContextPath() + "/other/toLogin");
            return false;
        }

        //多用户登录限制判断,并给出提示信息
        boolean isLogin = false;
        if (user != null) {
            Map<String, String> loginUserMap = (Map<String, String>) session.getServletContext().getAttribute("loginUserMap");
            String sessionId = session.getId();
            for (String key : loginUserMap.keySet()) {
                //用户已在另一处登录
                if (key.equals(user.getUserName()) && !loginUserMap.containsValue(sessionId)) {
                    isLogin = true;
                    break;
                }
            }
        }
        if (isLogin) {
            Map<String, String> loginOutTime = (Map<String, String>) session.getServletContext().getAttribute("loginOutTime");
            session.setAttribute("mess", "用户:" + user.getUserName() + ",于 " + loginOutTime.get(user.getUserName()) + " 已在别处登录!");
            loginOutTime.remove(user.getUserName());
            session.getServletContext().setAttribute("loginUserMap", loginOutTime);
            response.sendRedirect(request.getContextPath() + "/other/toLogin");
            return false;
        }

        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        super.afterCompletion(request, response, handler, ex);
    }
}

  3)在session销毁的时候,把loginUserMap中保存的键值对清除

public class SessionListener implements HttpSessionListener {

    private static Logger log = Logger.getLogger(SessionListener.class);

    @Override
    public void sessionCreated(HttpSessionEvent event) {

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        String sessionId = session.getId();
        //在session销毁的时候,把loginUserMap中保存的键值对清除
        User user = (User) session.getAttribute("now_user");
        if (user != null) {
            Map<String, String> loginUserMap = (Map<String, String>) event.getSession().getServletContext().getAttribute("loginUserMap");
            if(loginUserMap.get(user.getUserName()).equals(sessionId)){
                log.info("clean user from application : " + user.getUserName());
                loginUserMap.remove(user.getUserName());
                event.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);
            }
        }

    }

}

  4)web.xml

<!-- session listener 多用户登录限制,退出清除session信息的同时清除application中存放用户登录信息-->
  <listener>
    <listener-class>com.service.limitelogin.SessionListener</listener-class>
  </listener>

  5)页面代码(用于给出提示的同时,清除被挤掉用户的session信息,否则提示信息会一直显示) 

<script type="text/javascript">
    $(document).ready(function () {
        var message=‘${mess}‘;
        if (message != "") {
            $.ajax({
                       type: ‘GET‘,
                       async: false,
                       cache: false,
                       url: ‘/other/clearUserSession‘,
                       dataType: ‘‘,
                       data: {},
                       success: function (data) {
                       }
                   });
            $(‘#mess‘).html(message);
        }
    });
</script>

  6)清除挤掉用户session代码

/**
     * 多用户登录限制,清除session信息(登录信息、提示信息)
     *
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/clearUserSession")
    public String clearUserSession(HttpServletRequest request) {
        HttpSession httpSession = request.getSession();
        httpSession.invalidate();
        return "success";
    }

到此开发工作完成

4、运行结果

  

时间: 2024-08-10 23:49:21

多用户登录限制的相关文章

设置VNC多用户登录

1.安装VNCyum install vnc-server2.添加多个用户用户useradd user1  //添加用户user1passwd user1  //设置用户的linux登录密码su user1          //切换到用户user1vncpasswd      //设置用户的user1登录密码exituseradd user2  //添加用户user2passwd user2  //设置用户的linux登录密码su user2         //切换到用户user2vncpa

python 多用户登录

Python多用户登录 需求 让用户输入用户名密码 认证成功后显示欢迎信息 输错三次后退出程序 可以支持多个用户登录 (提示,通过列表存多个账户信息) 用户3次认证失败后,退出程序,再次启动程序尝试登录时,还是锁定状态(提示:需把用户锁定的状态存到文件里) 流程图 代码 1 #! /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 #多用户登录 4 5 user_list={ 6 'u01':{'password':'123'}, 7 'u02':{'

Asp .Net Core 2.0 登录授权以及多用户登录

用户登录是一个非常常见的应用场景 .net core 2.0 的登录方式发生了点变化,应该是属于是良性的变化,变得更方便,更容易扩展. 配置 打开项目中的Startup.cs文件,找到ConfigureServices方法,我们通常在这个方法里面做依赖注入的相关配置.添加如下代码: public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(CookieAuthentication

开启Win7多用户登录远程桌面

原文链接: http://blog.sina.com.cn/s/blog_7e5da5b101014fc4.html 多用户登陆破解:(支持win7 x86 & win7x64)在 Windows 7 中,远程登录默认只支持一个用户登陆.如果在登录时发现当前电脑已经有其他用户使用,会弹出提示,继续后会中断前面用户的操作.打开类似 Windows Server 的多用户登陆支持,需要修改 C:\Windows\System32\目录下的 termsrv.dll文件.  通过[Uedit32软件]十

作业1#python用列表实现多用户登录,并有三次机会

1 username = ["juebai","haha"] 2 password = [123,456] 3 count = 0 4 while count < 3: 5 _username = input("用户名:") 6 _password = int(input("密码:")) 7 if _username == username[0] and _password == password[0]: 8 print

Windows2012、windows2016配置多用户登录

windows系统多用户登录配置方法如下,但是120天后还是会提示缺少远程桌面授权服务器,根本解决办法,请参考: 服务器多用户登录可有效解决已登录用户被强制掉线的现象发生. 一.安装远程桌面服务依次点击:服务器管理器--管理--添加角色和功能 原文地址:http://blog.51cto.com/13777088/2299117

使用VNC实现多用户登录linux系统

vmare版本:12.0.0 build-2985596 vnc版本:VNC-Viewer-5.2.3-Windows-64bit linux系统:red hat enterprise 5 待解决问题:这种方式对于root账号没有配置成功,原因可能是vmare已经使用root账号登录 1.首先linux系统上存在多用户: 添加多个用户用户,举例: useradd shen  //添加用户shen passwd user1  //设置用户的linux登录密码 su - shen         

win7 多用户登录实现

//**************************这是安装的补丁,不知道有没有起到关键性的作用****************** 远程桌面服务使局域网 (LAN) 上的计算机可以连接到服务器(也称为远程计算机)并运行位于服务器上的程序.这可以只需要在1台机器上安装应用程序,其他机器共享使用.远程桌面连接使用远程桌面服务技术,使一台计算机可远程控制另一台计算机. windows 远程终端服务是单用户的,也就是说通过远程登录到服务器时,服务器本地将黑屏.如何做到不管用本地登录还是远程登录,同

多用户登录系统操作流程——Python多线程

# -*- coding: utf-8 -*- # @Time : 2019/1/3 10:03 # @Author : Philly # @File : multi_login.py # @Description: 多用户并发登录 from selenium import webdriver import threading from time import sleep from selenium.webdriver.common.action_chains import ActionChai