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

KeyCloak bearer-only客户端凭证错误仍可调用安全端点问题排查

问题根源与解决方案

这个问题其实是Spring Boot资源服务器和KeyCloak集成时的常见配置疏漏——核心是你的服务只验证了令牌本身的合法性(签名、过期时间),却没限制令牌的来源或受众,导致任何来自KeyCloak的有效令牌都能访问你的安全端点。下面具体分析原因和修复步骤:

核心原因:资源服务器未校验令牌的客户端/受众信息

当你用合法客户端cli1拿到令牌后,KeyCloak已经完成了对client-id和client-secret的验证——这一步是在令牌颁发阶段完成的,而你的Spring Boot服务作为资源服务器,默认职责只是确认令牌是由信任的KeyCloak签发、未过期的,但不会主动校验这个令牌是不是专门给你的服务(或指定客户端)颁发的。

具体来说,你可能遇到了以下几种配置问题:

1. 未配置aud(受众)验证

KeyCloak签发的JWT令牌里会包含aud字段,代表这个令牌的目标受众(比如某个客户端ID或资源ID)。如果你的服务没配置验证aud,那么任何来自该KeyCloak realm的有效令牌,不管它是给哪个客户端的,都会被服务端放行。

比如你的application.yml里可能缺少了关键的受众配置:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          audience: your-service-client-id  # 这里要填你的服务对应的KeyCloak客户端ID

2. 未通过权限(Scope)限制访问

就算令牌有效,如果你的服务没要求访问端点必须具备特定的scope,那么任何有效令牌都能访问。比如你可能没在安全配置里添加scope校验:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            // 要求访问/secure/**的令牌必须包含指定scope
            .requestMatchers("/secure/**").hasAuthority("SCOPE_your-required-scope")
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
    return http.build();
}

合法客户端cli1可能被KeyCloak配置了这个scope,但错误配置的客户端不会有,这样就能限制非法访问。

3. 资源服务器模式理解偏差

很多人会误以为资源服务器要重新验证client-id和client-secret,但其实这是客户端模式的逻辑——资源服务器的核心是验证令牌的合法性,而客户端身份已经在KeyCloak颁发令牌时验证过了。如果要限制只有特定客户端的令牌能访问,必须通过aud或scope来实现,而不是重复验证客户端凭证。

验证与修复步骤

  1. 解析令牌确认内容:用JWT解析工具(比如本地的JWT库或者离线解析工具)打开你的Bearer令牌,查看aud(受众)、azp(授权方,即签发该令牌的客户端ID)字段,确认这些值是否符合你的预期。
  2. 添加受众验证配置:在Spring Boot配置里指定audience,确保只有目标受众的令牌能被服务端接受。
  3. 配置权限限制:在安全配置中添加scope或角色校验,确保只有具备相应权限的令牌能访问安全端点。
  4. 检查KeyCloak客户端配置:确认你的服务对应的KeyCloak客户端Access Type和权限配置正确,比如是否给合法客户端分配了所需的scope。

给你一个完整的配置示例参考:

application.yml

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://your-keycloak-domain/auth/realms/your-realm
          audience: your-service-client-id

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/secure/**").hasAuthority("SCOPE_access-secure-api")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwtAuthenticationConverter(customJwtConverter())
                )
            );
        return http.build();
    }

    private JwtAuthenticationConverter customJwtConverter() {
        JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
        authoritiesConverter.setAuthorityPrefix("SCOPE_");
        authoritiesConverter.setAuthoritiesClaimName("scope");

        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
        return converter;
    }
}

这样配置后,只有包含正确aud和指定scope的令牌才能访问你的安全端点,其他不符合条件的令牌会被服务端拒绝。

内容的提问来源于stack exchange,提问作者codependent

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:23:17