我想实现一个过滤器来进行身份验证,但不知何故它被卡在无限循环中...任何想法都赞赏。
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
doBeforeProcessing(request, response);
Throwable problem = null;
HttpSession session = httpRequest.getSession(true);
if(session.getAttribute("userName")!=null&&session.getAttribute("userName")!=(""))
{
try {
chain.doFilter(request, response);
} catch (Throwable t) {
// If an exception is thrown somewhere down the filter chain,
// we still want to execute our after processing, and then
// rethrow the problem after that.
problem = t;
t.printStackTrace();
}
}else{
httpResponse.sendRedirect("login.jsp");
return;
}
这个代码在调试模式下运行无限次,基本上我想在用户未登录时将用户重定向到login.jsp。 任何答案都赞赏。
答案 0 :(得分:10)
下面,
httpResponse.sendRedirect("login.jsp");
您正在为目标网页发送新 HTTP请求,而不是使用当前请求。如果新的HTTP请求已经映射到过于通用的URL模式(例如/*
),那么这个新的HTTP请求当然会再次访问过滤器。并且将执行相同的检查,并且将再次重定向。等等。这是一个无休止的故事。
当当前请求的页面是登录页面时,您还需要添加额外的检查以执行FilterChain#doFilter()
。
String loginURL = httpRequest.getContextPath() + "/login.jsp";
if (httpRequest.getRequestURI().equals(loginURL)) || session.getAttribute("userName") != null) {
chain.doFilter(request, response);
} else {
httpResponse.sendRedirect(loginURL);
}
请注意,我还删除了对空字符串的无意义检查作为用户名(但您确保您的代码无法将空字符串设置为用户名。只需使用null
即可代表一个未登录的用户。另请注意,我也修复了重定向URL,因为当当前请求的URL位于子文件夹中时,它会失败。
另一种选择是将所有受限制的页面放在一个公共子文件夹中,例如/app
,/secured
,/restricted
等,然后将过滤器映射到{ {1}},/app/*
,/secured/*
等。如果您将登录页面保留在此文件夹之外,则在请求登录页面时不会调用过滤器。
答案 1 :(得分:5)
问题是您的过滤器正在login.jsp
上运行,当用户未登录时会反复重定向到自身。由于过滤器url-pattern
上没有排除语法,因此您需要检测过滤器中的网址,如果您已经在login.jsp
页面上,则省略重定向:
// your auth code
} else {
String redirect = httpRequest.getContextPath() + "/login.jsp";
String uri = httpRequest.getRequestURI().toString();
if (uri.endsWith(redirect)){
// URI ends with login.jsp, just process the chain
chain.doFilter();
} else {
// not on the login page and not logged in, redirect
httpResponse.sendRedirect(redirect);
return;
}
}