Spring OAuth2客户端凭证流:动态自定义Audience与Scope问题
场景
- Auth0应用(client-id/secret)
internal-services- 已授权调用apiA(受众:
http//apiA) - 已授权调用apiB(受众:
http//apiB)
- 已授权调用apiA(受众:
- 需要调用apiA和apiB的单体应用
- 微服务A(受众:
http//apiA) - 微服务B(受众:
http//apiB)
Spring单体应用配置
spring: security: oauth2: client: registration: auth0: client-id: bla client-secret: bla authorization-grant-type: client_credentials provider: auth0: issuer-uri: https://bla.au.auth0.com/
最初的实现思路
private OAuth2AccessToken getAccessToken(String audience, String scope) { OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest .withClientRegistrationId("auth0") .principal("monolith") .attributes(attrs -> { attrs.put("scope", scope); attrs.put("audience", audience); } ) .build(); OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(authorizeRequest); OAuth2AccessToken accessToken = authorizedClient.getAccessToken(); return accessToken; } public void doWorkA() { callApiA( data, getAccessToken("http//apiA", "customScopeA") ); } public void doWorkB() { callApiB( data, getAccessToken("http//apiB", "customScopeB") ); }
官方文档中的标准配置方式
@Bean public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() { RestClientClientCredentialsTokenResponseClient client = new RestClientClientCredentialsTokenResponseClient(); client.addParametersConverter(grantRequest -> { MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>(); parameters.set(OAuth2ParameterNames.AUDIENCE, "???"); parameters.set(OAuth2ParameterNames.SCOPE, "???"); return parameters; }); return client; }
遇到的问题
注册的ParameterConverter无法获取原始OAuth2AuthorizeRequest中的属性,缺少上下文信息。
疑问
- 是否有官方文档记载的方法可以实现需求?
- 接受更务实的实现方式(比如在
application.yml中重复配置,但无法在此指定audience)。 - Gemini建议复制
authorize方法实现自定义ClientCredentialsOAuth2AuthorizedClientProvider,但这种方式太繁琐。
希望存在简单直接的解决方案,只是自己没发现。
临时解决方案
- 该方案绕过了
OAuth2AuthorizedClientManager.authorize()的预期流程 - 会绕过框架的缓存等实用功能
使用示例
@Autowired private OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> tokenResponseClient; Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("audience", microserviceAudience); // 获取Auth0 M2M应用的客户端注册信息 ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId("auth0"); // 创建自定义授权请求,传入额外参数 CustomClientCredentialsGrantRequest grantRequest = new CustomClientCredentialsGrantRequest(clientRegistration, additionalParameters); // 使用配置的客户端执行客户端凭证流程 OAuth2AccessTokenResponse tokenResponse = tokenResponseClient.getTokenResponse(grantRequest); OAuth2AccessToken accessToken = tokenResponse.getAccessToken();
配置类
@Bean public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient() { DefaultClientCredentialsTokenResponseClient tokenResponseClient = new DefaultClientCredentialsTokenResponseClient(); // 使用自定义令牌请求增强器添加自定义参数 tokenResponseClient.setRequestEntityConverter(new CustomRequestEntityConverter()); return tokenResponseClient; }
转换器实现
public RequestEntity<?> convert(OAuth2ClientCredentialsGrantRequest grantRequest) { // 使用默认转换器获取标准RequestEntity RequestEntity<?> entity = defaultConverter.convert(grantRequest); if (entity == null) { return null; } // 如果是自定义请求类型,添加额外参数 if (grantRequest instanceof CustomClientCredentialsGrantRequest) { CustomClientCredentialsGrantRequest customRequest = (CustomClientCredentialsGrantRequest) grantRequest; ...创建包含自定义参数的新RequestEntity... } return entity; }
内容的提问来源于stack exchange,提问作者Oliver Henlich
相关产品推荐
相关产品推荐

