Java web实现账号单一登录,防止同一账号重复登录(踢人效果)

Java web实现账号单一登录,防止同一账号重复登录(踢人效果)的详细攻略如下:

1. 会话管理

要实现账号单一登录,需要使用会话来管理用户的登录状态。在用户登录时,我们可以将其登录信息写入Session,然后在用户每次访问需要权限的资源时,都要检查Session中是否存在该用户的登录信息。如果不存在,则说明该用户还未登录或已经退出登录,需要跳转到登录页面;如果存在,则说明该用户已经登录,可以继续访问需要权限的资源。

2. 避免重复登录

为了避免同一账号重复登录,我们可以在用户登录时,先检查该账号是否已经在其他地方登录。如果已经登录,则把之前的登录信息删除,并提示用户被踢出的原因。这个操作很容易使用Map来实现。Map中的key为账号,value为SessionId。当用户登录时,首先从Map中获取该账号的SessionId,如果SessionId存在且不等于当前SessionId,说明该用户在其他地方登录了,需要删除之前的Session信息。示例如下:

public class SessionListener implements HttpSessionListener {

    // 存储账号和SessionId
    private static Map<String, String> accountSessionMap = new ConcurrentHashMap<>();

    // Session创建时触发,将账号和SessionId存入map
    public void sessionCreated(HttpSessionEvent sessionEvent) {
        HttpSession session = sessionEvent.getSession();
        if (session.getAttribute("account") != null) {
            String account = (String) session.getAttribute("account");
            accountSessionMap.put(account, session.getId());
        }
    }

    // Session销毁时触发,将账号和SessionId从map中删除
    public void sessionDestroyed(HttpSessionEvent sessionEvent) {
        HttpSession session = sessionEvent.getSession();
        if (session.getAttribute("account") != null) {
            String account = (String) session.getAttribute("account");
            accountSessionMap.remove(account);
        }
    }

    // 检查账号是否已经在其他地方登录
    public static boolean checkAccountExists(String account, String sessionId) {
        String oldSessionId = accountSessionMap.get(account);
        if (oldSessionId != null && !oldSessionId.equals(sessionId)) {
            // 踢出之前的Session
            HttpSession session = SessionUtil.getSession(oldSessionId);
            if (session != null) {
                session.setAttribute("kickout", true);
                session.invalidate();
            }
            return true;
        }
        return false;
    }
}

3. 示例说明

示例1

在一个简单的网站上,用户需要登录才能查看个人信息。我们可以在登录成功后将用户信息写入Session,并将用户重定向到个人信息页面。如果用户已经登录过了,则要删除之前的Session信息,并跳转到登录页面。代码如下:

public class LoginServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String account = request.getParameter("account");
        String password = request.getParameter("password");

        // 验证账号密码是否正确
        if (checkAccount(account, password)) {
            HttpSession session = request.getSession();
            session.setAttribute("account", account);

            // 检查是否已经在其他地方登录
            if (SessionListener.checkAccountExists(account, session.getId())) {
                response.sendRedirect(request.getContextPath() + "/login.jsp");
            } else {
                response.sendRedirect(request.getContextPath() + "/user/info.jsp");
            }
        } else {
            response.sendRedirect(request.getContextPath() + "/login.jsp");
        }
    }
}

示例2

在一个在线考试系统中,要求每个考生只能在一个地方同时参加一次考试。我们可以在考生登录后将其考试Session的id写入Map中,然后在每个考试页面中检查该考生是否已经在其他地方参加考试。如果已经参加考试,则需要结束之前的考试并跳转到考试结果页面。代码如下:

public class ExamFilter implements Filter {

    private static Map<String, String> accountExamSessionMap = new ConcurrentHashMap<>();

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        HttpSession session = httpRequest.getSession(false);
        if (session == null || session.getAttribute("account") == null) {
            // 用户未登录
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
            return;
        }

        String account = (String) session.getAttribute("account");

        // 判断是否已经参加考试
        if (accountExamSessionMap.containsKey(account)) {
            String oldSessionId = accountExamSessionMap.get(account);
            HttpSession oldSession = SessionUtil.getSession(oldSessionId);
            if (oldSession != null) {
                oldSession.invalidate();
            }
            accountExamSessionMap.remove(account);
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/exam/result.jsp");
            return;
        }

        // 将考试Session的id写入Map中
        accountExamSessionMap.put(account, session.getId());

        chain.doFilter(request, response);
    }
}

这样,我们就完成了Java web实现账号单一登录,防止同一账号重复登录(踢人效果)的攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java web实现账号单一登录,防止同一账号重复登录(踢人效果) - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Mysql创建json字段索引的两种方式

    下面是关于MySQL创建JSON字段索引的两种方式的攻略。 方式一:使用虚拟列 准备工作 在 MySQL 5.7.8 版本及以后,支持通过自定义虚拟列的方式对表中的 JSON 字段进行索引。因此,在开始之前需要确保你的 MySQL 版本不低于 5.7.8。 操作步骤 接下来,我们假设有一个名为 users 的表,其中有一个 JSON 字段 info,现在我们…

    other 2023年6月25日
    00
  • Android获取、更改包名的小技巧分享(超实用)

    Android获取、更改包名的小技巧分享(超实用) 在Android开发中,有时候我们需要获取或者更改应用程序的包名。下面是一些实用的技巧,可以帮助你完成这些任务。 获取包名 要获取应用程序的包名,可以使用以下代码: String packageName = getPackageName(); 这将返回当前应用程序的包名。 更改包名 要更改应用程序的包名,需…

    other 2023年9月7日
    00
  • C语言进阶练习二叉树的递归遍历

    C语言进阶练习二叉树的递归遍历的完整攻略如下: 一、前序遍历 前序遍历指的是先遍历根节点,再遍历左子树,最后遍历右子树。递归实现前序遍历的代码如下: void preorderTraversal(TreeNode* root) { if(root == NULL) return; printf("%d ", root->val); …

    other 2023年6月27日
    00
  • js获取IP地址的方法小结

    JS获取IP地址的方法小结 在JavaScript中,获取用户的IP地址可以通过多种方法实现。下面是一些常用的方法和示例说明: 1. 使用第三方API 可以使用第三方提供的IP地址查询API来获取用户的IP地址。这些API通常会返回用户的IP地址和其他相关信息。 示例代码: fetch(‘https://api.ipify.org?format=json’)…

    other 2023年7月30日
    00
  • Qt实现电子时钟的示例代码

    这里是Qt实现电子时钟的示例代码的完整攻略。我会详细介绍这个过程,以便初学者也能理解。 环境准备 在开始编写代码之前,您需要确保您的电脑上安装了Qt Creator和Qt库。下面是安装的步骤: 下载Qt Creator,从Qt官方网站 – https://www.qt.io/download。 在安装程序上选择你的操作系统,下载安装程序后进行运行。 安装程序…

    other 2023年6月26日
    00
  • CSS 去除浏览器默认 轮廓外框

    CSS 去除浏览器默认轮廓外框 背景 在某些浏览器中,当用户聚焦到页面元素上时(例如链接、按钮等),会显示一个默认的蓝色或灰色边框,这被称为「轮廓外框」。然而,大部分网站的设计并不需要这个边框,甚至会影响到页面的美观度。如何去除这个默认的轮廓外框,就成了一个需要解决的问题。 解决方案 1. 使用 CSS 的 outline 属性将轮廓外框设为 0 可以通过下…

    其他 2023年3月28日
    00
  • Java代码编译和反编译的那些事儿

    Java代码编译和反编译是Java开发过程中的两个重要环节。编译是将Java源代码转换为字节码的过程,而反编译则是将字节码转换为Java源代码的过程。下面是详细讲解“Java代码编译和反编译的那些事儿”的完整攻略: 编译Java代码 编译Java代码的过程可以使用Java编译器javac来完成,可以按照以下步骤进行操作: 编写Java源代码,例如HelloW…

    other 2023年6月26日
    00
  • 条件数据库Android:sqllite的简单使用

    下面是“条件数据库Android:sqllite的简单使用”的完整攻略。 1. 前言 SQLite是一款功能强大的嵌入式关系型数据库,它被广泛应用在各个领域当中,而在Android中,SQLite是Android中的默认数据库,因此它也被广泛地应用在Android项目中。本篇文章将介绍在Android开发中如何使用SQLite数据库。 2. 实现SQLite…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部