首页 > 解决方案 > AuthenticationEntrypoint 不处理复杂的 AuthenticationException

问题描述

我正在尝试处理过滤器实现 AbstractPreAuthenticatedProcessingFilter 中引发的复杂 AuthenticationException ,如下所示。


public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
    if (authException instanceof UsernameNotFoundException) {
      response.sendRedirect("https://myapp.com/signup");
    }
    if (authException instanceof CredentialsExpiredException) {
      response.sendRedirect("https://myapp.com/update/password");
    }
    if (authException instanceof LockedException) {
      response.sendRedirect("https://myapp.com/support/1");
    }
    if (authException instanceof DisabledException) {
      response.sendRedirect("https://myapp.com/support/2");
    }
    if (authException instanceof AccountExpiredException) {
      response.sendRedirect("https://myapp.com/update/account");
    }
    if (authException instanceof InsufficientAuthenticationException) {
      System.out.println("#########InsufficientAuthenticationException########");
    }
}

从引发的每个异常

但是每次在我的测试中,都会在 MyAuthenticationEntryPoint 中捕获 InsufficientAuthenticationException。

这是我的 WebSecurityConfigurer。

@EnableWebSecurity
class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/error");
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .antMatchers("/hello").hasRole("HELLO");
    http.exceptionHandling().authenticationEntryPoint(new MyAuthenticationEntryPoint());
    http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
    http.addFilter(getMyPreAuthenticatedProcessingFilter());
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(getPreAuthenticatedAuthenticationProvider());
  }

  public AbstractPreAuthenticatedProcessingFilter getMyPreAuthenticatedProcessingFilter() throws Exception {
    var myPreAuthenticatedProcessingFilter = new MyPreAuthenticatedProcessingFilter();
    myPreAuthenticatedProcessingFilter.setAuthenticationManager(authenticationManager());
    return myPreAuthenticatedProcessingFilter;
  }

  public PreAuthenticatedAuthenticationProvider getPreAuthenticatedAuthenticationProvider() {
    var preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider();
    preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(new MyAuthenticationUserDetailsService());
    return preAuthenticatedAuthenticationProvider;
  }
}

我的猜测是

  1. PreAuthenticatedProcessingFilter 中出现异常。
  2. 由于 PreAuthenticatedProcessingFilter 中的身份验证设置失败,因此在 SecurityContext 中设置 AnonymousAuthenticationToken
  3. 在 FilterSecurityInterceptor 中,AnonymousAuthenticationToken 被拒绝并在 StackTrace 中保留 AccessDeniedException
  4. 在 ExceptionTranslationFilter 中,开始处理 Exception (AccessDeniedException) 如下

https://docs.spring.io/spring-security/site/docs/4.2.11.RELEASE/apidocs/org/springframework/security/web/access/ExceptionTranslationFilter.html

If an AccessDeniedException is detected, the filter will determine whether or not the user is an anonymous user. If they are an anonymous user, the authenticationEntryPoint will be launched. If they are not an anonymous user, the filter will delegate to the AccessDeniedHandler. By default the filter will use AccessDeniedHandlerImpl.

https://github.com/spring-projects/spring-security/blob/006b9b960797d279b31cf8c8d16f1549c5632b2c/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java#L126

  1. 最后调用 sendStartAuthentication 并将异常类型覆盖为 InsufficientAuthenticationException

https://github.com/spring-projects/spring-security/blob/006b9b960797d279b31cf8c8d16f1549c5632b2c/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java#L192

问:如何检测 AuthenticationEntryPoint 中的异常类型?

我正在尝试使用 AuthenticationFailureHandler 没有授权端点(等“/world”),成功检测 PreAuthenticatedProcessingFilter 中的异常类型。

但是通过授权,我不确定如何检测。无法使用授权端点检测 AuthenticationEntryPoint 中的异常类型?

http.authorizeRequests()
      .antMatchers("/hello").hasRole("HELLO");

标签: spring-security

解决方案


"response.isCommited()" with conditional in each error handler, I solved this problem, Thank you for your answer @jzheaux !


推荐阅读