【问题标题】:Keycloak get 401 error, but spring security does not handle this errorKeycloak 得到 401 错误,但是 spring security 不处理这个错误
【发布时间】:2020-09-13 04:16:55
【问题描述】:

问题如下。我像这样通过 Keycloak Bearer Spring security 实现了登录

public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Override
public void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
            .and()
            .csrf().disable()
            .addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
            .addFilterBefore(keycloakAuthenticationProcessingFilter(),               X509AuthenticationFilter.class)
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
            .and()
            .authorizeRequests().antMatchers(Constants.API_BASE_PATH + "/**").authenticated();
    }

}

当我发送空授权请求标头时,keycloak 会抛出错误 401。我无法像这样通过@ExceptionHandler 捕获:

@ExceptionHandler(RuntimeException.class)
protected ResponseEntity<Object> keycloakAuthenticationExceptionn(RuntimeException ex) {
    return buildResponseEntity(new ErrorResponseWrapper(BAD_REQUEST,new 
     MessageResponse(ex.getLocalizedMessage()),ex,ErrorCode.NOT_AUTHORIZED));
}

【问题讨论】:

    标签: spring spring-boot spring-security keycloak


    【解决方案1】:

    我不确定答案,但我遇到了类似您的问题。 ExceptionHandler 在 http 过滤器之后工作,因此在使用您的 ExceptionHandler 处理请求之前,可能会在他的过滤器中抛出 Keycloak 异常。因此,您可以跟踪整个日志以查看引发异常的位置。希望对你有帮助

    【讨论】:

    • 非常感谢您的回答!我发现当发送一个空的 Authorization 标头时,我在 keycloak 的响应标头中获得了两个相同的 WWW-Authenticate 标头。我认为因此我无法捕获 401 错误。在早期版本的 keycloak 中,出现了一个标题。一切都很好。
    【解决方案2】:
    **Thanks for answers!**
    
    I think, this is the problem:
    
    Earlier I used dependency keycloak version 4.0.0.Final
    pom.xml dependency
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-starter</artifactId>
            <version>4.0.0.Final</version>
        </dependency>
     and spring boot version 1.5.4.RELEASE. Everything worked great.
    Now I'm using spring boot version 2.1.5.RELEASE and keycloak version 10.0.1
    pom.xml dependency
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-2-adapter</artifactId>
            <version>10.0.1</version>
        </dependency>
    I checked it again from Postman when sending Authorization token "bearer " + "token" in the request header. I get a response with two the same WWW-Authenticate values ​​in the header.
    
    
    Earlier, header came in a single copy.
    
    Can you please tell me what the problem ?.
    

    【讨论】:

      【解决方案3】:

      KeyCloak 有一个处理身份验证失败的 KeycloakAuthenticationFailureHandler。 我能够通过创建自定义 KeycloakAuthenticationFailureHandler 来解决类似的问题,然后在覆盖的同时设置我的自定义类 KeycloakAuthenticationProcessingFilter.

      @Bean
          @Override
          protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
              KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(this.authenticationManagerBean());
              filter.setSessionAuthenticationStrategy(this.sessionAuthenticationStrategy());
              filter.setAuthenticationFailureHandler(new CustomKeycloakAuthenticationFailureHandler());
              return filter;
          }
      

      在我的自定义类中...

      public class CustomKeycloakAuthenticationFailureHandler implements AuthenticationFailureHandler {
      
      public CustomKeycloakAuthenticationFailureHandler() {}
      
      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
          if (!response.isCommitted()) {
              if (KeycloakCookieBasedRedirect.getRedirectUrlFromCookie(request) != null) {
                  response.addCookie(KeycloakCookieBasedRedirect.createCookieFromRedirectUrl((String)null));
              }
      
              //response.sendError(401, "Unable to authenticate using the Authorization header");
              response.setContentType("application/json");
              response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
              response.getOutputStream().println("{ \"error\": \"" + exception.getMessage() + "\" }");
          } else if (200 <= response.getStatus() && response.getStatus() < 300) {
              throw new RuntimeException("Success response was committed while authentication failed!", exception);
          }
      }
      

      }

      我可以使用响应 OutputStream 来自定义我对客户端的响应。 我评论了默认的 KeyCloak response.sendError 行。

      看起来 KeyCloak 在内部处理异常。

      此解决方案还解决了标头:WWW-Authenticate 的问题 在响应中不重复。

      为 KeyCloak 疑难解答开启 DEBUG 帮助:logging.level.org.keycloak=DEBUG

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2015-12-11
        • 2020-11-17
        • 2020-07-18
        • 2022-01-20
        • 1970-01-01
        • 2022-06-17
        • 2015-12-04
        • 2019-10-13
        • 2013-10-17
        相关资源
        最近更新 更多