扩展SimpleUrlAuthenticationFailureHandler生成404,找不到映射警告

时间:2016-10-06 15:20:09

标签: java spring spring-mvc spring-security

我正在尝试扩展SimpleUrlAuthenticationFailureHandler以在Spring安全性中的身份验证失败时实现一些自定义功能。我的所有配置都是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 security,如下所示;

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();

}

我已经使用failureUrl和2)使用自定义失败处理程序将org.springframework.security程序包放入调试模式日志记录中。在下面的日志片段中,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 个答案:

答案 0 :(得分:0)

正如其中一条评论中所提到的,即使登录页面与默认名称相同,即使用自定义登录表单也是有效的。查看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();
}