springsecurity ajax超時返回登入頁面
阿新 • • 發佈:2019-02-18
公司開發採用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錯誤:
@Component public 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); } }; }); });