Keycloak得到401错误,但是spring security不处理这个错误

1 spring spring-security spring-boot keycloak

问题如下。我通过 Keycloak Bearer Spring 安全性实现了登录,如下所示

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

}
Run Code Online (Sandbox Code Playgroud)

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

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

ari*_*ley 6

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;
    }
Run Code Online (Sandbox Code Playgroud)

在我的自定义课程中...

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

}

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

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

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

打开 DEBUG 进行 KeyCloak 故障排除帮助:logging.level.org.keycloak=DEBUG

希望这可以帮助。