Spring Boot集成Keycloak SAML登录报错:Invalid Request求助
解决Keycloak SAML 2.0登录时"Invalid Request"(client_not_found)问题
问题背景
使用Docker部署Keycloak 19.0.3,Spring Boot 2.7.3集成SAML 2.0登录,调用接口后可重定向到Keycloak地址http://localhost:8085/realms/PocRealm/protocol/saml,但显示"We are sorry ... Invalid Request"错误,Keycloak日志报错:
2022-10-07 12:22:41,972 WARN [org.keycloak.events] (executor-thread-104) type=LOGIN_ERROR, realmId=e026f301-c74b-4247-bb0a-58cdb651ae00, clientId=null, userId=null, ipAddress=172.17.0.1, error=client_not_found, reason=Cannot_match_source_hash
核心原因分析
该错误表明Keycloak无法匹配SAML请求中的客户端身份信息,通常由以下场景导致:
- Keycloak客户端配置与Spring应用配置不匹配
- 同时混用Keycloak官方适配器与Spring Security原生SAML2配置引发冲突
- SAML签名/哈希验证失败
- 元数据同步异常
解决方案
1. 检查Keycloak SAML客户端配置
- 创建正确类型的客户端:在
PocRealm中创建SAML类型的客户端,客户端ID必须与Spring配置中的registration.keycloak完全匹配(大小写敏感),不能使用OIDC客户端。 - 配置有效重定向URI:添加Spring Security SAML2默认回调地址
http://localhost:8081/login/saml2/sso/keycloak到客户端的Valid Redirect URIs列表中(若自定义了回调路径需同步修改)。 - 配置签名验证:若Spring应用配置了签名(
signing.credentials),需在Keycloak客户端开启Signature Required,并将Spring的证书myCert.crt上传到客户端的Signature Keys中。
2. 移除Spring配置冲突
你当前同时混用了Keycloak官方适配器配置(keycloak.*前缀)和Spring Security原生SAML2配置,这会导致逻辑冲突,需清理:
- 删除
application.properties中所有keycloak.*配置项,仅保留SAML2相关配置:# Spring Server Settings server.port=8081 #SAML Settings spring.security.saml2.relyingparty.registration.keycloak.signing.credentials[0].private-key-location=classpath:credentials/myKey.key spring.security.saml2.relyingparty.registration.keycloak.signing.credentials[0].certificate-location=classpath:credentials/myCert.crt spring.security.saml2.relyingparty.registration.keycloak.assertingparty.metadata-uri=http://localhost:8085/realms/PocRealm/protocol/saml/descriptor - 删除
KeycloakConfig.java类,移除所有Keycloak适配器相关Bean。 - 修改
SecurityConfig.java,替换@KeycloakConfiguration为@Configuration+@EnableWebSecurity,移除Keycloak适配器继承与相关方法,修正后的代码如下:@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider(); authenticationProvider.setResponseAuthenticationConverter(groupsConverter()); // @formatter:off http .authorizeHttpRequests(authorize -> authorize .mvcMatchers("/favicon.ico").permitAll() .anyRequest().authenticated() ) .saml2Login(saml2 -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ) .saml2Logout(withDefaults()); // @formatter:on return http.build(); } private Converter<OpenSaml4AuthenticationProvider.ResponseToken, Saml2Authentication> groupsConverter() { Converter<OpenSaml4AuthenticationProvider.ResponseToken, Saml2Authentication> delegate = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter(); return (responseToken) -> { Saml2Authentication authentication = delegate.convert(responseToken); Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal(); List<String> groups = principal.getAttribute("groups"); Set<GrantedAuthority> authorities = new HashSet<>(); if (groups != null) { groups.stream().map(SimpleGrantedAuthority::new).forEach(authorities::add); } else { authorities.addAll(authentication.getAuthorities()); } return new Saml2Authentication(principal, authentication.getSaml2Response(), authorities); }; } }
3. 验证SAML元数据有效性
- 测试Keycloak元数据地址
http://localhost:8085/realms/PocRealm/protocol/saml/descriptor是否可访问,确保返回完整的XML元数据。 - 确认Spring配置中的
assertingparty.metadata-uri指向正确地址,若Docker容器与Spring应用网络隔离,需调整地址为容器可访问的路径(如Docker内部IP)。
4. 排查签名/哈希验证问题
错误原因Cannot_match_source_hash指向签名验证失败:
- 确认
myKey.key与myCert.crt是配对的有效密钥对,无过期或格式错误。 - 若暂时不需要签名,可注释Spring配置中的
signing.credentials项,并关闭Keycloak客户端的Signature Required,测试是否能正常登录,以此排除签名问题。
内容的提问来源于stack exchange,提问作者DarkwingBug
相关产品推荐
相关产品推荐

