Spring Security 错误处理

2019-03-06  本文已影响0人  Gavin黄炯鹏

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);
    }
上一篇下一篇

猜你喜欢

热点阅读