1.Spring Security 简单介绍
spring security 是用来做安全验证的框架。默认状态下它有十个拦截器。使用者可以添加自定义拦截器并决定新增拦截器的顺序。一开始我以为像在controller层那样,遇到错误直接throw,但是这样做框架会跳到默认的错误页面,这不是我的需求。下面记录下错误处理的步骤.
2.新建错误处理器
新建自定义错误处理器,继承SimpleUrlAuthenticationFailureHandler类。框架默认使用的是这个类,onAuthenticationFailure是处理错误的方法,默认是跳到框架的验证入口(默认是登陆页面).这里做一些修改,假如是ajax请求,就返回json;假如不是,就跳到自定义页面.
public class SessionAuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger logger = Logger.getLogger(getClass());
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
logger.info("session过期");
if(isAjaxRequest(request)){
//返回json
response.setStatus(500);
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print(StrUtils.getResponseJson(e.getMessage(),false));
out.flush();
out.close();
}else{
String url = "/showTip";
//重定向到指定页面
getRedirectStrategy().sendRedirect(request, response, url);
}
}
private boolean isAjaxRequest(HttpServletRequest request) {
String header = request.getHeader("X-Requested-With");
if (header != null && "XMLHttpRequest".equals(header)){
return true;
}else{
return false;
}
}
}
3.新建自定义过滤器
新建过滤器,使用之前编写的错误处理器。在过滤器中捕捉SessionExpireException(继承AuthenticationException),然后执行之前重写的onAuthenticationFailure方法.
我看框架的过滤器链,其中倒数第二个是ExceptionTranslationFilter,它是用作处理security异常的过滤器,我以为不管在哪个过滤器发生错误,都要向下继续执行过滤器,后来我发现是不对的,所以ExceptionTranslationFilter这个过滤器的意义是什么呢?
public class SessionFilter extends OncePerRequestFilter {
private AuthenticationFailureHandler failureHandler = new SessionAuthenticationFailHandler();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getRequestURI().contains("/login") ||
request.getRequestURI().contains("/resources") ||
request.getRequestURI().contains("/view") ||
request.getRequestURI().contains("/common") ||
request.getRequestURI().contains("/captcha") ||
request.getRequestURI().equals("/admin/admin/baseSet") ||
request.getRequestURI().equals("/showTip")) {
filterChain.doFilter(request, response);
return ;
}
try {
isLogin(request);
}
catch (SessionExpireException e) {
failureHandler.onAuthenticationFailure(request, response, e);
return;//返回,不再向下执行.
}
filterChain.doFilter(request, response);
}
private void isLogin(HttpServletRequest request) throws AuthenticationException {
if (request.getSession().getAttribute(Constants.SESSION_LOGIN_USER) == null) {
throw new SessionExpireException();
}
}
}
public class SessionExpireException extends AuthenticationException {
public SessionExpireException() {
super("用户Session已过期");
// TODO Auto-generated constructor stub
}
}
4.将自定义过滤器加入框架中
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
// 把SessionFileter 放在 FilterSecurityInterceptor前面。
http.addFilterBefore(new SessionFilter(), FilterSecurityInterceptor.class);
}
网友评论