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

Spring项目中OAuth2 Client-ID配置错误仍可验证Token的原因解析

问题描述

在项目中使用Keycloak实现OAuth2认证时遇到如下现象:

  • 即使application.properties中配置了错误的client-id参数,项目仍能正常启动,且通过正确client_id从Keycloak获取的Token可通过验证
  • 无效Token会被安全层拦截

获取Token的请求参数

username:test
password:test1
client_id:client-payment
grant_type:password
client_secret:azgf9E8QZxG6lKAYbsYT1

application.properties中的关键错误配置

spring.security.oauth2.client.registration.keycloak.client-id=client-test

完整配置参数

spring.security.oauth2.client.registration.keycloak.provider=keycloak
spring.security.oauth2.client.registration.keycloak.client-id=client-test
spring.security.oauth2.client.registration.keycloak.client-secret=azgf9E8QZxG6lKAYbsYT1
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid,read,write
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8087/login/oauth2/code/keycloak


spring.security.oauth2.client.provider.keycloak.authorization-uri=http://localhost:8087/realms/realm-payment/protocol/openid-connect/auth
spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8087/realms/realm-/protocol/openid-connect/token
spring.security.oauth2.client.provider.keycloak.user-info-uri=http://localhost:8087/realms/realm-/protocol/openid-connect/userinfo
spring.security.oauth2.client.provider.keycloak.jwk-set-uri=http://localhost:8087/realms/realm-/protocol/openid-connect/certs
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.client.provider.keycloak.user-info-authentication-method=header

安全配置类

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig {

    private final AuthenticationEntryPoint authenticationEntryPoint;

    private final AuthenticationEntryPoint tokenAuthenticationEntryPoint;

    private final CustomAuthenticationManagerResolver customAuthenticationManagerResolver;

    public SecurityConfig(
            @Qualifier("customAuthenticationEntryPoint") AuthenticationEntryPoint authenticationEntryPoint,
            @Qualifier("tokenAuthenticationEntryPoint") AuthenticationEntryPoint tokenAuthenticationEntryPoint,
            CustomAuthenticationManagerResolver customAuthenticationManagerResolver) {
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.tokenAuthenticationEntryPoint = tokenAuthenticationEntryPoint;
        this.customAuthenticationManagerResolver= customAuthenticationManagerResolver;
    }

    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
            http
                    .cors().and()
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and().exceptionHandling()
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .and()
                    .oauth2ResourceServer().authenticationEntryPoint(tokenAuthenticationEntryPoint)
                    .authenticationManagerResolver(request -> customAuthenticationManagerResolver.resolveAuthenticationManager());
        return http.build();
    }
}

问题解析

核心原因:服务角色为资源服务器,客户端配置未被使用

你的服务通过oauth2ResourceServer()配置为OAuth2资源服务器,核心职责是验证请求中的Token合法性;而spring.security.oauth2.client.registration.*属于OAuth2客户端的配置,仅当服务需要主动向授权服务器(Keycloak)申请Token时才会生效。资源服务器的Token验证逻辑完全不依赖客户端注册配置中的client-id,因此即使配置错误也不会影响验证。

配置参数的具体含义与作用阶段

1. 客户端注册配置(spring.security.oauth2.client.registration.keycloak.*)

仅服务作为OAuth2客户端时生效:

  • client-id/client-secret:客户端在Keycloak中的身份凭证,用于客户端向Keycloak申请Token时的身份校验
  • authorization-grant-type:授权类型,你配置的authorization_code是跳转登录的授权码模式,但实际使用的是密码模式获取Token,这部分配置未生效
  • scope:客户端请求的权限范围,仅在申请Token时生效
  • redirect-uri:授权码模式下,Keycloak授权完成后跳转回服务的地址

2. 提供者配置(spring.security.oauth2.client.provider.keycloak.*)

部分参数被资源服务器用到:

  • jwk-set-uri:Keycloak的公钥集合地址,资源服务器通过该地址获取公钥,验证Token的签名合法性(Token验证的核心步骤)
  • authorization-uri/token-uri/user-info-uri:客户端模式下的请求地址,资源服务器无需使用
  • user-name-attribute:从用户信息接口提取用户名的字段,仅当资源服务器主动拉取用户信息时生效

错误client-id不影响Token验证的深层逻辑

资源服务器验证Token的核心流程:

  1. 解析Token为JWT格式
  2. 通过jwk-set-uri获取的公钥验证Token签名是否有效
  3. 检查Token的exp(过期时间)、nbf(生效时间)是否符合当前时间
  4. (默认不开启)验证Token的iss(发行者)、aud(受众)等声明

默认情况下,资源服务器不会验证Token中的client_id字段,也不会读取客户端注册配置里的client-id——因为Token的合法性已经由Keycloak在颁发时完成校验,只要签名有效、未过期,资源服务器就会认可该Token。

无效Token被拦截的原因

无效Token会在上述验证步骤中失败:

  • 签名错误:无法通过公钥验证,直接判定无效
  • 过期/未生效:Token的时间戳不符合当前时间
  • 格式错误:无法解析为标准JWT格式

这些失败情况都会触发Spring Security的拦截逻辑,返回未授权响应。

额外提示

你配置的客户端授权类型是authorization_code,但实际使用password模式获取Token,这组配置完全不匹配,但因为服务是资源服务器,所以不会影响运行。如果后续服务需要作为客户端主动获取Token(比如调用其他服务),则需要修正授权类型配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:32:32