如何在Java Web应用程序中Session过期时redirect到Login页面?
我正在JBoss AS 5中运行一个Web应用程序。我也有一个servletfilter,拦截所有到服务器的请求。 现在,如果会话已过期,我想将用户redirect到login页面。 我需要做这个'isSessionExpired()'检查filter,并需要相应的redirect用户。 我该怎么做? 我在web.xml中设置会话时间限制,如下所示:
<session-config> <session-timeout>15</session-timeout> </session-config>
您可以使用filter并执行以下testing:
HttpSession session = request.getSession(false);// don't create if it doesn't exist if(session != null && !session.isNew()) { chain.doFilter(request, response); } else { response.sendRedirect("/login.jsp"); }
上面的代码是未经testing的 。
但这并不是最广泛的解决scheme。 您还应该在会话中testing某个特定于域的对象或标志是否可用,然后才能假定由于会话不是新用户必须login的。
如何在Java Web应用程序中Session过期时redirect到Login页面?
这是一个错误的问题。 您应该区分“用户未login”和“会话已过期”的情况。 当用户没有login时,基本上要redirect到login页面,而不是在会话过期时。 目前接受的答案只检查HttpSession#isNew()
。 但是,当用户在会话由JSP隐式创build或者没有创build会话时,在同一会话中发送了多个请求时,这显然会失败。 例如,只需按login页面上的F5即可。
如上所述,您应该检查用户是否已login。 鉴于你问这样的问题,而标准的authentication框架,如j_security_check
,Shiro,Spring Security等已经透明地pipe理这个问题(因此不需要问这种问题),只能意味着你正在使用本地的身份validation方法。
假设您将login用户存储在某个loginservlet中的会话中,如下所示:
@WebServlet("/login") public class LoginServlet extends HttpServlet { @EJB private UserService userService; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); User user = userService.find(username, password); if (user != null) { request.getSession().setAttribute("user", user); response.sendRedirect(request.getContextPath() + "/home"); } else { request.setAttribute("error", "Unknown login, try again"); doGet(request, response); } } }
然后你可以在下面的loginfilter中检查:
@WebFilter("/*") public class LoginFilter implements Filter { @Override 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); String loginURI = request.getContextPath() + "/login"; boolean loggedIn = session != null && session.getAttribute("user") != null; boolean loginRequest = request.getRequestURI().equals(loginURI); if (loggedIn || loginRequest) { chain.doFilter(request, response); } else { response.sendRedirect(loginURI); } } // ... }
没有必要摆弄脆弱的HttpSession#isNew()
检查。
你也可以用这样的filter来做到这一点:
public class RedirectFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)request; //check if "role" attribute is null if(req.getSession().getAttribute("role")==null) { //forward request to login.jsp req.getRequestDispatcher("/login.jsp").forward(request, response); } else { chain.doFilter(request, response); } } }
你可以在本教程中看到其余部分
检查会话是新的。
HttpSession session = request.getSession(false); if (!session.isNew()) { // Session is valid } else { //Session has expired - redirect to login.jsp }
在filter内部注入这个会带来这样的login页面的JavaScript。 如果您不这样做,那么在您的AJAX调用中,您将获得login页面,login页面的内容将被追加。
在你的filter或redirect内插入这个脚本作为回应:
String scr = "<script>window.location=\""+request.getContextPath()+"/login.do\"</script>"; response.getWriter().write(scr);
你需要实现HttpSessionListener
接口,服务器会通知会话超时。
喜欢这个;
import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class ApplicationSessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent event) { System.out.println("Session Created"); } public void sessionDestroyed(HttpSessionEvent event) { //write your logic System.out.println("Session Destroyed"); } }
检查这个例子,以更好的理解
在会话超时之前,我们得到一个正常的请求,之后我们得到一个Ajax请求。 我们可以通过以下方式来识别它:
String ajaxRequestHeader = request.getHeader("X-Requested-With"); if ("XMLHttpRequest".equals(ajaxRequestHeader)) { response.sendRedirect("/login.jsp"); }
我发现这个可行的解决scheme:
public void logout() { ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext(); String ctxPath = ((ServletContext) ctx.getContext()).getContextPath(); try { //Use the context of JSF for invalidate the session, //without servlet ((HttpSession) ctx.getSession(false)).invalidate(); //redirect with JSF context. ctx.redirect(ctxPath + "absolute/path/index.jsp"); } catch (IOException ex) { System.out.println(ex.getMessage()); } }
当使用login时,将其用户名放在会话中:
`session.setAttribute("USER", username);`
在每一页的开始,你可以这样做:
<% String username = (String)session.getAttribute("USER"); if(username==null) // if session is expired, forward it to login page %> <jsp:forward page="Login.jsp" /> <% { } %>