案例1:退出登录:一旦我们退出登录,如果有人试图访问以前的页面,它必须自动重定向到login.jsp。
案例2:会话过期:如果用户仍然登录时会话过期,则在访问以前的页面时必须尝试自动重定向到sessionExpired.jsp。
如何区分?我目前在注销时使会话无效。
案例1:退出登录:一旦我们退出登录,如果有人试图访问以前的页面,它必须自动重定向到login.jsp。
案例2:会话过期:如果用户仍然登录时会话过期,则在访问以前的页面时必须尝试自动重定向到sessionExpired.jsp。
如何区分?我目前在注销时使会话无效。
登录时,设置一个过期时间长的cookie(> 24小时)。在注销时通过将maxage设置为0来删除此cookie。
您可以检查任何非登录用户(即无效的会话ID)。如果cookie不存在,请将其重定向到login.jsp。
如果cookie存在,则表示其会话已过期,请将其重定向到session-expired.jsp。
HttpServletRequest#getRequestedSessionId()
是否返回null
来测试已过期的会话(这意味着客户端已发送会话cookie,因此假定会话仍然有效),并且HttpServletRequest#isRequestedSessionIdValid()
返回false
(这意味着会话在服务器端已过期)。简言之:public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
response.sendRedirect(request.getContextPath() + "/sessionexpired.jsp");
} else if (session == null || session.getAttribute("user") == null) {
response.sendRedirect(request.getContextPath() + "/login.jsp");
} else {
chain.doFilter(request, response);
}
}
不需要麻烦处理额外的cookies。将此Filter
映射到覆盖受保护页面(因此排除了会话过期和登录页面!)的url-pattern
上。
不要忘记在受保护的页面上禁用浏览器页面缓存,否则当您在浏览器历史记录中返回时,Web浏览器将从缓存中加载它们,而不是向服务器发送新请求。您可以通过在同一过滤器中,在Chain#doFilter()
调用之前执行以下操作来实现此目的。
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
如果是我,我会在注销时清除会话并在其中创建一个名为HasLoggedOut的布尔变量,然后将其设置为true。然后如果会话中存在这个布尔变量,你就知道他们已经注销了;如果不存在,那么会话可能已经超时或者用户根本没有登录。
由于你仍然无法区分超时和未登录的情况,我通常会做出这样的决定:如果他们请求一个需要身份验证的页面,我会直接将他们发送到会话超时页面,这也可以作为一个登录页面,上面显示类似于以下内容的提示:
"哎呀,我们不知道你是谁,你的会话可能已经超时或者你还没有登录,请在下面登录"
这样可以同时适应这两种情况。