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

如何在OAuth2令牌请求中添加自定义参数生成带自定义声明的令牌?

在Spring Security OAuth2中为Client Credentials令牌请求添加自定义参数

Q1 解答

Spring Security OAuth2的组件按职责分层设计:

  • OAuth2AuthorizeRequest是授权流程的入口请求对象,承载触发授权的上下文信息(客户端ID、用户主体、自定义属性等),面向顶层的OAuth2AuthorizedClientManager。
  • OAuth2ClientCredentialsGrantRequest是Client Credentials授权类型的专用请求对象,仅聚焦该授权类型所需的核心标准化信息(客户端注册信息、授权类型),是底层TokenResponseClient处理令牌请求的输入。

两者属于流程的不同阶段,框架默认没有在OAuth2ClientCredentialsGrantRequest中保留OAuth2AuthorizeRequest的引用或属性——因为GrantRequest的设计目标是标准化授权类型的请求参数,而非传递上层上下文的自定义数据。

基于框架的解决方案

方案一:扩展GrantRequest传递自定义参数(通用场景)

通过扩展OAuth2ClientCredentialsGrantRequest来携带自定义参数,配合自定义的AuthorizedClientProvider和请求转换器完成参数传递。

  1. 自定义GrantRequest类
public class CustomClientCredentialsGrantRequest extends OAuth2ClientCredentialsGrantRequest {
    private final Map<String, String> customParameters;

    public CustomClientCredentialsGrantRequest(OAuth2ClientCredentialsGrantRequest originalRequest, Map<String, String> customParameters) {
        super(originalRequest.getClientRegistration());
        this.customParameters = customParameters;
    }

    public Map<String, String> getCustomParameters() {
        return customParameters;
    }
}
  1. 自定义ClientCredentials授权提供者
    重写authorize方法,从OAuth2AuthorizationContext中提取OAuth2AuthorizeRequest的自定义属性,创建自定义GrantRequest实例:
public class CustomClientCredentialsOAuth2AuthorizedClientProvider extends ClientCredentialsOAuth2AuthorizedClientProvider {
    @Override
    public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
        // 从授权请求中提取自定义属性
        Map<String, String> customParams = context.getAuthorizeRequest().getAttributes().entrySet().stream()
                .filter(entry -> entry.getKey().startsWith("custom_")) // 自定义属性前缀标识
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toString()));

        // 创建自定义GrantRequest
        OAuth2ClientCredentialsGrantRequest originalGrantRequest = new OAuth2ClientCredentialsGrantRequest(context.getClientRegistration());
        CustomClientCredentialsGrantRequest customGrantRequest = new CustomClientCredentialsGrantRequest(originalGrantRequest, customParams);

        // 配置支持自定义GrantRequest的转换器
        DefaultClientCredentialsTokenResponseClient tokenResponseClient = (DefaultClientCredentialsTokenResponseClient) getTokenResponseClient();
        tokenResponseClient.setRequestEntityConverter(new CustomOAuth2ClientCredentialsGrantRequestEntityConverter());

        try {
            OAuth2TokenResponse tokenResponse = tokenResponseClient.getTokenResponse(customGrantRequest);
            return new OAuth2AuthorizedClient(
                    context.getClientRegistration(),
                    context.getPrincipalName(),
                    tokenResponse.getAccessToken(),
                    tokenResponse.getRefreshToken()
            );
        } catch (OAuth2AuthorizationException ex) {
            throw ex;
        }
    }
}
  1. 自定义请求实体转换器
    重写createParameters方法,读取自定义GrantRequest中的参数并添加到令牌请求体:
public class CustomOAuth2ClientCredentialsGrantRequestEntityConverter extends OAuth2ClientCredentialsGrantRequestEntityConverter {
    @Override
    protected MultiValueMap<String, String> createParameters(OAuth2ClientCredentialsGrantRequest grantRequest) {
        MultiValueMap<String, String> parameters = super.createParameters(grantRequest);
        // 读取自定义参数并添加到请求体
        if (grantRequest instanceof CustomClientCredentialsGrantRequest customRequest) {
            customRequest.getCustomParameters().forEach(parameters::add);
        }
        return parameters;
    }
}
  1. 配置OAuth2AuthorizedClientManager
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientService authorizedClientService) {

    CustomClientCredentialsOAuth2AuthorizedClientProvider clientCredentialsProvider = new CustomClientCredentialsOAuth2AuthorizedClientProvider();
    DefaultOAuth2AuthorizedClientManager manager = new DefaultOAuth2AuthorizedClientManager(
            clientRegistrationRepository,
            authorizedClientService
    );
    manager.setAuthorizedClientProvider(clientCredentialsProvider);
    return manager;
}
  1. 调用示例
// 构建授权请求时添加自定义属性
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("my-client")
        .attribute("custom_parameter1", "user-specific-value")
        .attribute("custom_parameter2", "another-value")
        .build();

OAuth2AuthorizedClient authorizedClient = oauthClientManager.authorize(authorizeRequest);

方案二:利用RequestAttribute传递参数(Web环境专属)

如果是Web应用,可以通过RequestContextHolder在请求上下文中传递自定义参数,适合不需要跨线程传递的场景。

  1. 自定义请求实体转换器
public class CustomOAuth2ClientCredentialsGrantRequestEntityConverter extends OAuth2ClientCredentialsGrantRequestEntityConverter {
    @Override
    protected MultiValueMap<String, String> createParameters(OAuth2ClientCredentialsGrantRequest grantRequest) {
        MultiValueMap<String, String> parameters = super.createParameters(grantRequest);
        // 从当前请求上下文获取自定义参数
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            String customParam1 = (String) requestAttributes.getAttribute("custom_parameter1", RequestAttributes.SCOPE_REQUEST);
            if (customParam1 != null) {
                parameters.add("custom_parameter1", customParam1);
            }
        }
        return parameters;
    }
}
  1. 配置TokenResponseClient
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientService authorizedClientService) {

    ClientCredentialsOAuth2AuthorizedClientProvider clientCredentialsProvider = new ClientCredentialsOAuth2AuthorizedClientProvider();
    // 配置自定义转换器
    DefaultClientCredentialsTokenResponseClient tokenResponseClient = new DefaultClientCredentialsTokenResponseClient();
    tokenResponseClient.setRequestEntityConverter(new CustomOAuth2ClientCredentialsGrantRequestEntityConverter());
    clientCredentialsProvider.setTokenResponseClient(tokenResponseClient);

    DefaultOAuth2AuthorizedClientManager manager = new DefaultOAuth2AuthorizedClientManager(
            clientRegistrationRepository,
            authorizedClientService
    );
    manager.setAuthorizedClientProvider(clientCredentialsProvider);
    return manager;
}
  1. 调用示例
// 先将自定义参数放入当前请求上下文
RequestContextHolder.getRequestAttributes().setAttribute(
        "custom_parameter1",
        "web-request-value",
        RequestAttributes.SCOPE_REQUEST
);

// 构建并执行授权请求
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("my-client").build();
OAuth2AuthorizedClient authorizedClient = oauthClientManager.authorize(authorizeRequest);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:44:59