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

SpringBoot应用用JWT客户端断言遇AADSTS900144错误的排查解决

解决AADSTS900144错误:JWT客户端断言模式下client_id缺失问题

1. 检查自定义资源细节类的client_id配置

确保你的JwtOAuth2ProtectedResourceDetails类正确继承AuthorizationCodeResourceDetails,且配置Bean时显式设置clientId属性,不能仅添加断言相关配置。示例代码:

@Bean
public JwtOAuth2ProtectedResourceDetails azureADResourceDetails() {
    JwtOAuth2ProtectedResourceDetails details = new JwtOAuth2ProtectedResourceDetails();
    details.setClientId("your-client-id"); // 必须显式配置
    details.setClientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT);
    details.setTokenUri("https://login.microsoftonline.com/your-tenant-id/oauth2/v2.0/token");
    // 补充JWT断言相关配置:如密钥库路径、密钥别名、密码等
    return details;
}

2. 修复OAuth2RestTemplate的参数组装逻辑

默认的OAuth2RestTemplate在JWT断言模式下可能存在参数遗漏问题,需自定义ClientCredentialsAccessTokenProvider强制将client_id放入请求体:

@Bean
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails resourceDetails) {
    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
    ClientCredentialsAccessTokenProvider provider = new ClientCredentialsAccessTokenProvider() {
        @Override
        protected void prepareRequest(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) {
            super.prepareRequest(request, resource, form);
            // 强制添加client_id到请求体,避免缺失
            form.add("client_id", resource.getClientId());
        }
    };
    restTemplate.setAccessTokenProvider(provider);
    return restTemplate;
}

3. 确认客户端认证方法配置匹配

根据你的签名方式,正确设置clientAuthenticationMethod:

  • 若使用客户端密钥签名JWT,设置为ClientAuthenticationMethod.CLIENT_SECRET_JWT
  • 若使用私钥签名JWT,设置为ClientAuthenticationMethod.PRIVATE_KEY_JWT,同时配置密钥库相关参数:
details.setClientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
details.setJwtKeyStore(new ClassPathResource("your-keystore.jks"));
details.setJwtKeyAlias("your-key-alias");
details.setJwtKeyPassword("your-key-password");

4. 调试请求体参数验证

添加请求拦截器打印实际发送的令牌请求体,确认client_id是否存在:

restTemplate.getInterceptors().add((request, body, execution) -> {
    if (request.getURI().toString().contains("/token")) {
        System.out.println("Token request body: " + new String(body, StandardCharsets.UTF_8));
    }
    return execution.execute(request, body);
});

如果打印结果无client_id,需重新调整令牌提供者的参数组装逻辑。

5. 对比Python脚本的请求参数

将Spring发送的请求参数与Python成功请求的参数逐一对比,确保client_id、grant_type、client_assertion_type、client_assertion等必填参数完全一致,注意授权码模式下grant_type为authorization_code,需同时携带code和redirect_uri。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:17:13