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

Spring Authorization Server中如何在client_credentials授权类型下扩展Token端点接收额外参数并生成关联的AccessToken?

Spring Authorization Server中如何在client_credentials授权类型下扩展Token端点接收额外参数并生成关联的AccessToken?

你选的方向完全没错!实现AuthenticationConverter和OAuth2TokenGenerator<OAuth2AccessToken>正是在Spring Authorization Server中扩展client_credentials授权、处理额外参数并生成关联Token的核心路径。下面我会一步步帮你把整个流程补全,确保能实现你想要的效果:


1. 完善自定义AuthenticationConverter,提取并传递额外参数

首先要从Token端点的请求中提取额外参数,并把它注入到认证流程的Authentication对象中,这样后续的Token生成逻辑就能拿到这个参数。我们可以基于默认的OAuth2ClientCredentialsAuthenticationConverter做扩展:

import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

public class CustomClientCredentialsAuthenticationConverter implements AuthenticationConverter {

    // 复用默认转换器处理基础参数(grant_type、client_id、client_secret等)
    private final OAuth2ClientCredentialsAuthenticationConverter delegate = new OAuth2ClientCredentialsAuthenticationConverter();

    @Override
    public Authentication convert(HttpServletRequest request) {
        Authentication authentication = delegate.convert(request);
        
        if (authentication instanceof OAuth2ClientCredentialsAuthenticationToken clientCredentialsToken) {
            // 提取你的额外参数,这里假设参数名为"custom_param"
            String customParam = request.getParameter("custom_param");
            
            // 可选:验证参数是否必填
            if (!StringUtils.hasText(customParam)) {
                throw new OAuth2AuthenticationException(
                    new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, "缺少必填参数:custom_param", null)
                );
            }
            
            // 将额外参数存入Authentication的details字段,供后续流程使用
            Map<String, Object> updatedDetails = new HashMap<>(clientCredentialsToken.getDetails());
            updatedDetails.put("custom_param", customParam);
            
            // 返回包含额外参数的新认证Token
            return new OAuth2ClientCredentialsAuthenticationToken(
                clientCredentialsToken.getClientPrincipal(),
                updatedDetails,
                clientCredentialsToken.getAuthorities()
            );
        }
        
        return authentication;
    }
}

2. 实现自定义TokenGenerator,关联额外参数生成AccessToken

接下来要在Token生成阶段,把额外参数关联到AccessToken中——可以把参数存入Token的Claims里,也可以基于参数生成唯一的Token(确保同一客户端不同参数生成不同Token):

import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2AccessTokenGenerator;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
import org.springframework.util.StringUtils;

public class CustomOAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OAuth2AccessToken> {

    private final DefaultOAuth2AccessTokenGenerator delegate = new DefaultOAuth2AccessTokenGenerator();

    @Override
    public OAuth2AccessToken generate(OAuth2TokenContext context) {
        // 从认证Token中取出之前存入的额外参数
        if (context.getAuthentication() instanceof OAuth2ClientCredentialsAuthenticationToken clientCredentialsToken) {
            String customParam = (String) clientCredentialsToken.getDetails().get("custom_param");
            
            if (StringUtils.hasText(customParam)) {
                // 将额外参数写入Token的Claims,方便后续接口或资源服务器获取
                context.getClaims().claim("custom_param", customParam);
                
                // 如果你需要让Token与client_id+custom_param绑定(同一客户端不同参数生成不同Token)
                // 由于Spring Authorization Server默认会为每个不同的认证请求生成独立的OAuth2Authorization记录
                // 只要参数不同,就会生成不同的授权记录,自然会生成不同的Token,这一步通常无需额外操作
            }
        }
        
        // 调用默认生成器完成Token的最终生成
        return delegate.generate(context);
    }

    @Override
    public boolean supports(OAuth2TokenContext context) {
        // 仅支持AccessToken的生成
        return delegate.supports(context);
    }
}

3. 配置自定义组件到授权服务器流程

最后要把上面两个自定义组件注册到Spring Authorization Server的配置中,替换默认的转换器和生成器:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;

@Configuration
@EnableWebSecurity
public class AuthorizationServerConfig {

    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        // 应用授权服务器默认安全配置
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .tokenEndpoint(tokenEndpoint -> tokenEndpoint
                        // 替换client_credentials授权的请求转换器
                        .accessTokenRequestConverter(new CustomClientCredentialsAuthenticationConverter())
                        // 配置自定义的AccessToken生成器
                        .accessTokenGenerator(new CustomOAuth2AccessTokenGenerator())
                );
        
        return http.build();
    }

    // 请根据你的需求添加其他必要的Bean,比如RegisteredClientRepository、ClientRegistrationRepository等
    // ...
}

测试验证

完成配置后,你可以用Postman或curl调用Token端点,示例请求:

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=your-client-id&client_secret=your-client-secret&custom_param=your-custom-value

你可以通过解析返回的AccessToken(用JWT解析工具)查看Claims中是否包含custom_param字段,同时测试不同的custom_param值是否会生成不同的AccessToken。

备注:内容来源于stack exchange,提问作者hugoalexandremf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 07:47:57