Расширение SimpleUrlAuthenticationFailureHandler выдает 404 без предупреждения о том, что сопоставление не найдено

#java #spring #spring-mvc #spring-security

#java #весна #spring-mvc #spring-безопасность

Вопрос:

Я пытаюсь расширить SimpleUrlAuthenticationFailureHandler , чтобы достичь некоторой пользовательской функциональности при сбое аутентификации в spring security. Вся моя конфигурация находится в коде Java, Поэтому нет файлов безопасности xml и т. Д. код для CustomAuthenticationFailureHandler выглядит следующим образом;

 public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{

    public CustomAuthenticationFailureHandler(String defaultFailureUrl) {
        super(defaultFailureUrl);
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        String userName = request.getParameter("username");
        System.out.println("Invalid login attempt by user "   userName);
        // This performs custom auditing upon each login failure
        userLogRepository.logUserActivity(userName, -1, request.getRemoteHost(), exception);
        super.onAuthenticationFailure(request, response, exception);
    }
}
  

и этот обработчик применяется к безопасности Spring, как показано ниже;

 public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;

@Autowired
@Qualifier("userLogRepository")
UserLogRepository userLogRepository;

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

    auth.userDetailsService(userDetailsService);
}

@Override
protected void configure(HttpSecurity http) throws Exception {

     CsrfTokenResponseHeaderBindingFilter csrfTokenFilter = new CsrfTokenResponseHeaderBindingFilter();
     http.addFilterAfter(csrfTokenFilter, CsrfFilter.class);


     http.authorizeRequests().antMatchers("/rest/**").access("hasRole('ROLE_REST_USER')")
        .and().formLogin().successHandler(new CustomLoginSuccessHandler(new AjaxAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler())))
        // If I use the following failureUrl method it all seems to work correctly but then I don't have the custom implementaiton. 
        //.failureUrl("/login?error=1").permitAll()
        .failureHandler(new CustomAuthenticationFailureHandler("/login?error=1"))
        .and().logout().invalidateHttpSession(true).addLogoutHandler(new CustomLogoutSuccessHandler()).permitAll()
        .and().exceptionHandling().accessDeniedPage("/403")
        .and().csrf();

}
  

Я поместил пакет org.springframework.security в ведение журнала в режиме отладки для обеих конфигураций 1) с использованием failureUrl и 2) с использованием пользовательского обработчика сбоев. В приведенных ниже фрагментах журнала DefaultLoginPageGeneratingFilter , похоже, правильно перенаправляется на «/ login?error = 1», если используется конфигурация failureUrl.

Использование метода failureUrl (это работает)

 2016-10-06 15:43:24,839 [http-bio-8080-exec-5 : DEBUG] SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error=1
2016-10-06 15:43:24,839 [http-bio-8080-exec-5 : DEBUG] DefaultRedirectStrategy : Redirecting to '/web-console/login?error=1'
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@798d735c
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:43:24,840 [http-bio-8080-exec-5 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-10-06 15:43:24,843 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-10-06 15:43:24,843 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@4ef1ae10. A new one will be created.
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 5 of 14 in additional filter chain; firing Filter: 'CsrfTokenResponseHeaderBindingFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 6 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /login
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] FilterChainProxy : /login?error=1 at position 8 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@798d735c
2016-10-06 15:43:24,844 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:43:24,845 [http-bio-8080-exec-6 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
  

Использование пользовательского обработчика сбоев (это не работает)

 2016-10-06 15:37:20,413 [http-bio-8080-exec-6 : DEBUG] DefaultRedirectStrategy : Redirecting to '/web-console/login?error=1'
2016-10-06 15:37:20,413 [http-bio-8080-exec-6 : DEBUG] HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@26019c88
2016-10-06 15:37:20,414 [http-bio-8080-exec-6 : DEBUG] HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-10-06 15:37:20,414 [http-bio-8080-exec-6 : DEBUG] SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2016-10-06 15:37:20,417 [http-bio-8080-exec-7 : DEBUG] HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@58e4d010. A new one will be created.
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 5 of 14 in additional filter chain; firing Filter: 'CsrfTokenResponseHeaderBindingFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 6 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /login
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 8 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 9 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] DefaultSavedRequest : pathInfo: both null (property equals)
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] DefaultSavedRequest : queryString: arg1=null; arg2=error=1 (property not equals)
2016-10-06 15:37:20,418 [http-bio-8080-exec-7 : DEBUG] HttpSessionRequestCache : saved request doesn't match
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 10 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 99432565D3173E5497B49BC0DF428692; Granted Authorities: ROLE_ANONYMOUS'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] AntPathRequestMatcher : Checking match of request : '/login'; against '/rest/**'
2016-10-06 15:37:20,419 [http-bio-8080-exec-7 : DEBUG] FilterSecurityInterceptor : Public object - authentication not attempted
2016-10-06 15:37:20,420 [http-bio-8080-exec-7 : DEBUG] FilterChainProxy : /login?error=1 reached end of additional filter chain; proceeding with original chain
  

Я прикрепил только соответствующие фрагменты журнала, поскольку в режиме отладки создается много журналов, которые, я думаю, не имеют отношения к делу, однако дайте мне знать, если потребуется, я могу добавить больше.

Я не уверен, что я что-то упускаю в конфигурации здесь. Кто-нибудь, пожалуйста, посоветуйте мне, как мне следует подходить к сценарию перенаправления URL-адреса сбоя при использовании пользовательского обработчика сбоев?

Комментарии:

1. @dur Ok, это имеет смысл. Я загрузил исходный код и подтвердил, что failureUrl будет установлен только в DefaultLoginPageGeneratingFilter том случае, если используется метод failureUrl. Но вопрос по-прежнему остается тем же, как мне обрабатывать перенаправление в таком сценарии.

2. @dur Спасибо, использование пользовательской страницы входа сработало, даже если имя страницы входа совпадает с именем по умолчанию, т.Е. /login .

Ответ №1:

Как упоминалось в одном из комментариев, использование пользовательской формы входа в систему сработало, даже если страница входа имеет то же имя, что и по умолчанию, т.е. /login . Просмотр его кода DefaultLoginPageGeneratingFilter устанавливает URL-адрес выхода из системы и сбоя только в том случае, если обработчик сбоев не используется. Моя рабочая WebSecurityConfigurerAdapter конфигурация выглядит так, как показано ниже;

 @Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService)/*.passwordEncoder(new BCryptPasswordEncoder())*/;
}

@Override
protected void configure(HttpSecurity http) throws Exception {

     http.addFilterAfter(csrfTokenFilter, CsrfFilter.class);

     http.authorizeRequests().antMatchers("/rest/**").access("hasRole('ROLE_REST_USER')")
        .and().formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
        .successHandler(loginSuccessHandler)
        .failureHandler(authenticationFailureHandler).permitAll()
        .and().logout().invalidateHttpSession(true).addLogoutHandler(logoutSuccessHandler).permitAll()
        .and().exceptionHandling().accessDeniedPage("/403")
        .and().csrf();
}