登录页面刷新时会话超时
Posted
技术标签:
【中文标题】登录页面刷新时会话超时【英文标题】:Session timeout upon refresh at login page 【发布时间】:2012-07-01 23:54:24 【问题描述】:我制作了一个非常简单的登录和会话结构,以便在我未来的基于 JSP 的应用程序中重用。是这样的:
web.xml(1分钟超时是为了测试我的问题):
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<filter>
<filter-name>Access</filter-name>
<filter-class>com.app.Access</filter-class>
</filter>
<filter-mapping>
<filter-name>Access</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>com.app.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
Access.java 过滤器:
// Check if the page's the login or if the user logged, else asks login
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException
HttpServletRequest httpRequest = (HttpServletRequest) request;
boolean logged = httpRequest.getSession(false) != null && httpRequest.getSession().getAttribute("user") != null;
if (httpRequest.getServletPath().equals("/login") || logged)
chain.doFilter(request, response);
else
((HttpServletResponse) response).sendRedirect(httpRequest.getContextPath() + "/login");
Login.java servlet(为测试缩短验证):
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid())
request.setAttribute("failure", "session timeout");
request.getSession().setAttribute("user", null);
request.getRequestDispatcher("login.jsp").forward(request, response);
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
request.getSession().setAttribute("user", new User());
response.sendRedirect("");
login.jsp 页面位于 WebContent 的根目录,有一个 <form action="login" method="post">
表单,其中包含用于身份验证的适当的 innerhtml 和一个用于接收的 $failure 字段会话超时或登录失败消息。
这种结构非常适合我。它拦截、请求登录、检查会话和身份验证等,但有一个小缺陷:如果您在登录页面并在超时后刷新它(F5 或在 URL 处按 Enter),页面接收并在 $failure 中显示“会话超时”消息。
我还没有找到真正的工作方法来让它知道前一页是登录页。尝试了大约五种不同的方法,包括request.getHeader("Referer")
和lastWish
标签库。
【问题讨论】:
【参考方案1】:一种方法是让您的可公开访问的 JSP(例如登录页面)不创建会话。默认情况下,请求 JSP 页面即隐式创建会话。这可以通过在 JSP 顶部添加以下行来实现:
<%@page session="false" %>
这样request.getRequestedSessionId()
将返回null
,从而绕过超时检查。只有在您实际登录用户时才会以这种方式创建会话。我只会从 servlet 中删除以下行,因为这没有任何意义并且仍然会创建会话:
request.getSession().setAttribute("user", null);
【讨论】:
我不知道可以做这样的事情!我添加了它以重置用户,以防他手动进入登录页面,但使用您的解决方案我更喜欢删除它。非常感谢,BalusC! 不客气。由于您是新来的,所以不要忘记在回答(最)有助于解决具体问题时将其标记为已接受。另见How does accepting an answer work? @Trevor:漂亮的边缘案例。通常,在一般的自尊网站中,已经登录的用户不会看到任何“登录”链接(因为这在用户体验方面令人困惑)并且任何通过强制 URL 或跟随链接/书签来访问它的尝试都会导致在重定向到主页时,可能带有“您已经登录”消息。对于该重定向,可以使用过滤器(可能是您可能已经在使用的相同身份验证过滤器)。 不错的提示,我也会努力在我的结构中实现它。顺便说一句,我发誓我已经标记了答案,对不起!【参考方案2】:我只是这样做:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
HttpServletRequest httpReq = (HttpServletRequest)request;
String servletPath = httpReq.getServletPath();
HttpSession session = httpReq.getSession();
String redirectUrl = "/login.jsp";
if (
(servletPath.endsWith("login.jsp")) ||
(servletPath.endsWith("rss.html")) ||
(servletPath.endsWith("httperror403.html")) ||
(servletPath.endsWith("httperror500.html")) ||
(servletPath.endsWith("imageMark.do"))||
(servletPath.indexOf("/api.do") != -1) ||
(servletPath.indexOf("/help/") != -1))
chain.doFilter(request, response);
else if (session == null)
httpReq.getRequestDispatcher(redirectUrl).forward(request, response);
else
SystemUser user = (SystemUser)session.getAttribute("user");
if (user == null)
if (session != null)
session.invalidate();
httpReq.getRequestDispatcher(redirectUrl).forward(request, response);
else
chain.doFilter(request, response);
【讨论】:
这究竟如何回答 OP 的具体问题?顺便说一句,您的代码中存在逻辑缺陷。session
在此构造中从不 null
。以上是关于登录页面刷新时会话超时的主要内容,如果未能解决你的问题,请参考以下文章
JSF 2 + Spring 3 + Shiro - 会话超时不重定向到登录页面