You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:01:34