问题背景
目前系统使用的基于拦截器Interceptor的登录验证似乎出了些问题,有些情况下在Controller层获取session中的用户数据时失败。具体原因没有找到,组长说应该是Interceptor这块出了些问题,于是打算将登录验证放到Filter上去做。
基本业务逻辑
1 判断请求url是否需要进行登录验证;
2 如果需要登录验证,则判断是否有登录的用户数据,否则执行过滤器链中的下一个过滤器;
3 如果用户未登录,转跳到登陆页;否则执行过滤器链中的下一个过滤器
堆代码
package com.shtd.common.filter;
import java.io.IOException;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import com.shtd.common.util.LoginConstants;
import com.shtd.modules.edu.roll.entity.vo.StuUser;
public class LoginFilter extends OncePerRequestFilter{
private String excludedPages;
private String[] excludedPageArray;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// System.out.println(" ==登录过滤==" + request.getServletPath());
HttpSession session = request.getSession();
StuUser curUser = (StuUser)session.getAttribute(LoginConstants.SESSION_KEY_CURUSER);
if (curUser == null || curUser.getId() == null){
// System.out.println(" ==未通过==");
response.sendRedirect(request.getContextPath()+ "/login");
} else {
// System.out.println(" ==通过==");
filterChain.doFilter(request, response);
}
}
/**
* 初始化时获得参数
*/
@Override
protected void initFilterBean() throws ServletException {
// System.out.println("初始化 登录过滤器");
excludedPages = getFilterConfig().getInitParameter("exclusions");
if (StringUtils.isNotEmpty(excludedPages)) {
excludedPageArray = excludedPages.split(",");
for (int i=0; i < excludedPageArray.length; i++) {
String excludedPage = excludedPageArray[i];
if (excludedPage.contains("**")){
StringBuilder builder = new StringBuilder();
builder.append("^");
builder.append(StringUtils.replace(excludedPage, "**", "\\S*"));
builder.append("$");
excludedPageArray[i] = builder.toString();
}
// System.out.println(excludedPageArray[i]);
}
}
}
/**
* 是否要跳过过滤器
*/
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
if (excludedPageArray == null || excludedPageArray.length == 0) {
return false;
}
String path = request.getServletPath();
for (String excludedPage : excludedPageArray) {
if (StringUtils.isBlank(excludedPage)) {
continue;
}
if (excludedPage.startsWith("^")){
if (Pattern.matches(excludedPage, path)) {
return true;
}
} else if (excludedPage.equals(path)) {
return true;
}
}
return false;
}
}
配置文件
<!-- 登录状态过滤 -->
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.shtd.common.filter.LoginFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>/login,/init-pwd,/authenticate,/resources/**</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 登录状态过滤, 结束-->
值得注意的点
1 Filter没有类似于Interceptor的exclude-mapping的设置——严重觉得可能是我没找到——只能通过init-param来传入要忽略的路径;
2 一般情况下,实现javax.servlet.Filter就行了,然后我发现继承spring的OncePerRequestFilter会更方便一些。它将init和destroy方法都封装好了,我们只需要关注于doFilter这块。同时也提供和获得传入参数和是否需要进入过滤器的判断方法,只要重写相应的方法就行了
3 记得通过过滤后,执行filterChain.doFilter(request, response);