杰瑞科技汇

java session过期判断

Session 是如何管理过期的?

要理解 Session 过期的判断机制,就必须了解 Session 的生命周期,Session 的状态通常存储在服务器上,客户端通过一个名为 JSESSIONID 的 Cookie 来关联服务器上的 Session。

java session过期判断-图1
(图片来源网络,侵删)

Session 的过期主要有两种方式:

  1. 被动过期 (服务器端超时):这是最常见的方式,当客户端在一定时间内(30 分钟)没有对该 Session 发送任何请求,服务器就会认为该 Session 已不再活跃,并将其标记为过期,服务器会随后在特定的时间(当服务器内存紧张或 Session 监听器触发时)清理掉这些过期的 Session 对象。

    • 这个“一定时间”由 web.xml 配置文件中的 <session-config><session-timeout> 标签(单位:分钟)来控制。
    • 在 Servlet 3.0+ 中,也可以通过 HttpSessionsetMaxInactiveInterval(int interval) 方法(单位:秒)在代码中动态设置。
  2. 主动过期 (手动销毁):开发者可以在代码中显式地调用 session.invalidate() 方法来立即销毁 Session,通常用于“安全退出”或“用户注销”功能。

判断 Session 是否过期,本质上就是检查服务器上存储的该 Session 对象是否还存在且有效。

java session过期判断-图2
(图片来源网络,侵删)

判断 Session 过期的几种方法

根据不同的使用场景(在 Servlet、Filter、JSP 中),有几种常用的方法。

直接获取 Session 并检查其属性(最常用)

这是最直接的方法,你可以尝试从 HttpServletRequest 中获取 HttpSession 对象,然后检查它是否为 null,或者检查一个特定的、你用来标记用户登录状态的属性是否存在。

关键点

  • Session 已经过期,request.getSession(false) 会返回 null
  • request.getSession() 会在 Session 不存在时创建一个新的 Session,这通常不是我们想要的行为,尤其是在判断登录状态时。

示例代码 (在 Servlet 或 Filter 中):

java session过期判断-图3
(图片来源网络,侵删)
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class SessionCheckUtil {
    // 假设我们用 "user" 这个属性来标记用户已登录
    private static final String USER_ATTRIBUTE = "user";
    /**
     * 检查 Session 是否存在且用户已登录
     * @param request HttpServletRequest 对象
     * @return true: Session 有效且用户已登录; false: Session 无效或用户未登录
     */
    public static boolean isSessionValid(HttpServletRequest request) {
        // 使用 getSession(false) 来避免在 Session 不存在时创建新 Session
        HttpSession session = request.getSession(false);
        // 1. 首先检查 Session 对象本身是否存在
        if (session == null) {
            System.out.println("Session 已过期或不存在。");
            return false;
        }
        // 2. 检查 Session 中是否存在用户登录信息
        //    这是一个更精确的判断,防止 Session 存在但用户信息已丢失的情况
        Object user = session.getAttribute(USER_ATTRIBUTE);
        if (user == null) {
            System.out.println("Session 存在,但用户信息已丢失。");
            return false;
        }
        System.out.println("Session 有效,用户: " + user);
        return true;
    }
}

在 Filter 中进行全局拦截(推荐用于权限控制)

这是一种更优雅、更符合“关注点分离”原则的方法,你可以创建一个 Filter,对所有需要登录才能访问的 URL 进行拦截,并在 Filter 中统一检查 Session 的有效性。

工作流程:

  1. 客户端发送请求到受保护的资源(如 /dashboard, /profile)。
  2. 请求先经过 LoginCheckFilter
  3. Filter 调用 SessionCheckUtil.isSessionValid(request) 进行判断。
  4. 如果有效,则放行 (chain.doFilter(request, response))。
  5. 如果无效,则重定向到登录页面 (response.sendRedirect("login.jsp"))。

示例代码 (Filter):

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = {"/dashboard", "/profile", "/protected/*"})
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        // 使用我们上面创建的工具类进行检查
        if (SessionCheckUtil.isSessionValid(req)) {
            // Session 有效,放行请求
            chain.doFilter(request, response);
        } else {
            // Session 无效,重定向到登录页面
            System.out.println("访问被拒绝,Session 无效,重定向到登录页。");
            res.sendRedirect(req.getContextPath() + "/login.jsp");
        }
    }
    // 其他 Filter 方法...
}

在 JSP 中使用 EL 表达式(用于页面显示)

在 JSP 页面中,你经常需要根据用户的登录状态来显示不同的内容(显示“欢迎,张三”或“请登录”)。

示例代码 (JSP):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>首页</title>
</head>
<body>
    <h1>欢迎来到我们的网站</h1>
    <%-- 使用 EL 表达式判断 sessionScope 中是否存在 user 对象 --%>
    <%-- ${sessionScope.user} 会尝试从 session 中获取 "user" 属性 --%>
    <%-- session 过期或 user 属性不存在,表达式结果为 null,条件为 false --%>
    <c:if test="${not empty sessionScope.user}">
        <p>欢迎您, ${sessionScope.user.name}! <a href="<c:url value='/logout'/>">安全退出</a></p>
    </c:if>
    <c:if test="${empty sessionScope.user}">
        <p><a href="<c:url value='/login.jsp'/>">请登录</a></p>
    </c:if>
</body>
</html>

注意: <%@ page isELIgnored="false" %> 确保了 JSP 容器会处理 EL 表达式,需要引入 JSTL 核心标签库 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


最佳实践与注意事项

  1. 配置合理的超时时间:

    • web.xml 中设置一个合理的全局超时时间。
      <session-config>
      <session-timeout>30</session-timeout> <!-- 30分钟 -->
      </session-config>
    • 对于某些关键操作(如修改密码),可以临时通过 session.setMaxInactiveInterval(300) 将超时时间缩短到 5 分钟,操作结束后再恢复。
  2. 不要在 Session 中存储敏感信息:

    Session 存储在服务器内存中,虽然相对安全,但仍需防范内存泄露和序列化攻击,绝不要将密码、信用卡号等明文敏感信息存入 Session,可以只存一个用户 ID 或 Token,然后通过 ID 去数据库查询详细信息。

  3. 妥善处理客户端 Cookie:

    • 默认情况下,JSESSIONID Cookie 是基于会话的(浏览器关闭即失效),如果需要“记住我”功能,需要将 Cookie 的 max-age 设置为一个较大的值(7天),这时,你需要在服务端实现一个更复杂的机制来验证这个长期有效的 Cookie 是否仍然对应一个有效的 Session。
  4. 使用 getSession(false):

    • 再次强调,在检查 Session 是否存在时,始终优先使用 request.getSession(false),以避免无意中创建一个空的新 Session,这可能会导致逻辑混乱和安全漏洞。
  5. 清理资源:

    • HttpSessionListenersessionDestroyed 方法中,执行一些清理工作,从在线用户列表中移除该用户、关闭数据库连接等。
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    public class MySessionListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent se) {
            System.out.println("Session 创建: " + se.getSession().getId());
        }
        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            System.out.println("Session 销毁: " + se.getSession().getId());
            // 在这里进行清理工作
            //  OnlineUserManager.removeUser(se.getSession().getId());
        }
    }

完整示例:登录与 Session 过期处理

这是一个简单的登录流程,展示了如何创建 Session、使用 Filter 检查以及处理过期。

登录 Servlet (LoginServlet.java)

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 简单的硬编码验证,实际项目中应查询数据库
        if ("admin".equals(username) && "password".equals(password)) {
            // 登录成功,创建 Session 并存入用户信息
            HttpSession session = request.getSession();
            session.setAttribute("user", new User(username)); // 假设有一个 User 类
            response.sendRedirect("dashboard.jsp");
        } else {
            // 登录失败,返回登录页并提示错误
            request.setAttribute("error", "用户名或密码错误");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        }
    }
}

登录页面 (login.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>登录</title>
</head>
<body>
    <h2>用户登录</h2>
    <%-- 显示错误信息 --%>
    <c:if test="${not empty error}">
        <p style="color:red;">${error}</p>
    </c:if>
    <form action="<c:url value='/login'/>" method="post">
        用户名: <input type="text" name="username"><br>
        密码:   <input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

受保护页面 (dashboard.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>控制面板</title>
</head>
<body>
    <h1>控制面板</h1>
    <p>欢迎, ${sessionScope.user.username}!</p>
    <a href="<c:url value='/logout'/>">退出登录</a>
</body>
</html>

退出 Servlet (LogoutServlet.java)

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate(); // 手动销毁 Session
        }
        response.sendRedirect("login.jsp");
    }
}

LoginCheckFilter (如前所述)

这个 Filter 会保护 /dashboard/profile,当用户未登录时访问这些页面,会被自动重定向到 login.jsp

判断 Java Session 是否过期,核心是 request.getSession(false)检查 Session 内的关键属性,对于权限控制,使用 Filter 进行统一拦截是最佳实践,理解 Session 的生命周期和配置,并结合客户端的 Cookie 处理,可以构建出健壮、安全的 Web 应用。

分享:
扫描分享到社交APP
上一篇
下一篇