springsecurity ajax超时返回登录页面

来源:互联网 发布:网络公开课网站 编辑:程序博客网 时间:2024/05/15 23:48

公司开发采用Spring Security+AngualerJS框架,在session过期之后,ajax请求会直接出错。本文介绍如何实现出错情况下自动跳转至登录页。

  整体思路是,session过期后,ajax请求返回401 unauthentication错误,前端对$http服务添加拦截器,对401错误进行跳转处理,跳转至登录页。

  由于session过期,需要验证的请求(不论是不是ajax请求)会返回302重定向,我们先配置spring security使之能对ajax请求返回401错误。如下:

  实现自定义的RequestMatcher,当请求是ajax请求即匹配上(angular默认不会带上X-Requested-With,这里通过Accept进行判断,也可以在前端对ajax请求添加X-Requested-With头):

复制代码
public static class AjaxRequestMatcher implements RequestMatcher {    @Override    public boolean matches(HttpServletRequest request) {        return "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) ||                request.getHeader("Accept") != null &&                     request.getHeader("Accept").contains("application/json");    }}
复制代码

  实现自定义的AuthenticationEntryPoint,返回401错误:

复制代码
@Componentpublic class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {    @Override    public void commence(HttpServletRequest request, HttpServletResponse response,            AuthenticationException authException) throws IOException, ServletException {        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);    }}
复制代码

  配置错误处理,对ajax请求使用AjaxAuthenticationEntryPoint(

  .exceptionHandling()
        .defaultAuthenticationEntryPointFor(authenticationEntryPoint, new AjaxRequestMatcher())):

复制代码
    @Autowired    private AuthenticationEntryPoint authenticationEntryPoint;        protected void configure(HttpSecurity http) throws Exception {        http            .headers()                .cacheControl()                .and()            .authorizeRequests()                .antMatchers(                    "/login",                    "/css/**",                    "/img/**",                    "/js/**",                    "/partial/**",                    "/script/**",                    "/upload/**",                    "/plugin/**").permitAll()                .antMatchers("/**")                .authenticated()                .and()            .formLogin()                .loginPage("/login")                .permitAll()                .defaultSuccessUrl("/app.html", true)                .and()            .logout()                .logoutUrl("/logout")                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))                .logoutSuccessUrl("/login")                .and()            .exceptionHandling()                .defaultAuthenticationEntryPointFor(authenticationEntryPoint, new AjaxRequestMatcher())                .and()            .csrf().disable();    }
复制代码

  前端,添加拦截器:

复制代码
angular.module('app', []).config(function($httpProvider) {    $httpProvider.interceptors.push(function($q, $window) {          return {            // optional method            'request': function(config) {              // do something on success              return config;            },            // optional method           'requestError': function(rejection) {              // do something on error              if (canRecover(rejection)) {                return responseOrNewPromise              }              return $q.reject(rejection);            },            // optional method            'response': function(response) {              // do something on success              return response;            },            // optional method           'responseError': function(rejection) {              // do something on error              if (rejection.status === 401) {//                return responseOrNewPromise                  console.log('401');                  $window.location.href = 'login?expired';              }              return $q.reject(rejection);            }          };        });});
0 0