我制作了一个非常简单的登录和会话结构,以便在我未来基于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("");
}
位于WebContent根目录的 login.jsp 页面有<form action="login" method="post">
表单,其中包含适用于身份验证的innerHTML和 $ {failure} 字段接收会话超时或登录失败消息。
这种结构对我来说非常适合。它拦截,请求登录,检查会话和身份验证等,但是有一个小缺陷:如果您在登录页面并在超时后刷新它(F5或在URL处按Enter键),页面接收并显示$ {failure}中的“会话超时”消息。
我发现还没有真正的工作方式让它知道前一页是登录页面。尝试了五种不同的方法但没有成功,包括request.getHeader("Referer")
和lastWish
标记库。
答案 0 :(得分:2)
一种方法是让您可公开访问的JSP(例如登录页面)不创建会话。请求JSP页面默认情况下隐式创建会话。这可以通过在JSP的顶部添加以下行来实现:
<%@page session="false" %>
这样request.getRequestedSessionId()
将返回null
,因此将绕过超时检查。会话将以这种方式然后仅在您实际登录用户时创建。我只从servlet中删除以下行,因为这没有任何意义,仍然会创建会话:
request.getSession().setAttribute("user", null);
答案 1 :(得分:0)
我就是这样做的:
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);
}
}
}