spring - Keycloak 得到 401 错误,但是 spring security 没有处理这个错误
问题描述
问题如下。我像这样通过 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();
}
}
当我将 Authorization 请求标头发送为空时,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));
}
解决方案
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 在内部处理异常。
此解决方案还解决了 header: WWW-Authenticate 在响应中不重复的问题。
为 KeyCloak 故障排除打开 DEBUG 帮助:logging.level.org.keycloak=DEBUG
希望这可以帮助。
推荐阅读
- html - 帕格在包裹中的使用
- linux - 在 PATH terraform 中设置路径
- php - 如何在 WooCommerce 中下订单后获取购买数据并将其作为 POST 请求发送?
- php - 使用自定义 ID 和自定义消息在 PHP 中处理错误
- asp.net-core - IIS 应用程序池关闭时间限制(秒)设置是否有 IIS Express 等效项?
- r - 使用R中的distm()计算数据帧中两个GPS位置之间的距离
- wpf - 防止禁用控制或效果库的项目代码?
- linq - 具有大于和小于日期条件的 LINQ 左外连接
- c++ - 跳过第 3 方库中的 #define
- math - 找到垂直点与直线相交的 x 和 y 坐标