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

如何在新版Spring Authorization Server中添加自定义Token Granter

Spring Authorization Server 替换默认Token Granter及自定义JWT声明实现方案

一、替换/自定义Token Granter(替代旧版AbstractTokenGranter)

新版Spring Authorization Server不再沿用旧版AbstractTokenGranter的继承模式,而是通过**自定义AuthenticationProvider**来实现自定义授权类型的处理,步骤如下:

1. 定义自定义授权类型与认证Token

先声明你的自定义授权类型(比如sso_grant),并创建对应的认证Token类,用来承载请求参数:

public class SsoOAuth2AuthorizationGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
    // 自定义授权类型标识
    public static final String GRANT_TYPE = "sso_grant";

    public SsoOAuth2AuthorizationGrantAuthenticationToken(
            ClientRegistration clientRegistration,
            Authentication clientPrincipal,
            Map<String, Object> additionalParameters) {
        super(new OAuth2AuthorizationGrant(GRANT_TYPE), clientPrincipal, additionalParameters);
    }
}

2. 实现自定义AuthenticationProvider

这是核心逻辑,在这里你可以调用外部服务、处理用户认证、生成令牌:

@Component
public class SsoOAuth2TokenGrantAuthenticationProvider implements AuthenticationProvider {
    private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
    private final OAuth2AuthorizationService authorizationService;
    // 注入你的用户服务(用来获取用户信息)
    private final UserService userService;

    // 构造方法注入依赖
    public SsoOAuth2TokenGrantAuthenticationProvider(
            OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator,
            OAuth2AuthorizationService authorizationService,
            UserService userService) {
        this.tokenGenerator = tokenGenerator;
        this.authorizationService = authorizationService;
        this.userService = userService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SsoOAuth2AuthorizationGrantAuthenticationToken authToken = 
                (SsoOAuth2AuthorizationGrantAuthenticationToken) authentication;
        
        // 1. 从请求参数中提取用户标识(比如user_id)
        String userId = (String) authToken.getAdditionalParameters().get("user_id");
        
        // 2. 调用外部服务获取用户信息(角色、姓名、邮箱等)
        UserInfo userInfo = userService.getUserInfoById(userId);
        
        // 3. 构建用户认证主体,包含权限信息
        Collection<GrantedAuthority> authorities = userInfo.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
        Authentication userAuthentication = new UsernamePasswordAuthenticationToken(
                userInfo, null, authorities);

        // 4. 创建授权信息构建器
        OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(authToken.getRegisteredClient())
                .principalName(userAuthentication.getName())
                .authorizationGrantType(new OAuth2AuthorizationGrant(GRANT_TYPE))
                .attribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME, authToken.getRegisteredClient().getScopes());

        // 5. 生成Access Token(如果需要Refresh Token,后续会自动处理)
        OAuth2TokenContext tokenContext = OAuth2TokenContext.builder()
                .registeredClient(authToken.getRegisteredClient())
                .principal(userAuthentication)
                .authorization(authorizationBuilder.build())
                .tokenType(OAuth2TokenType.ACCESS_TOKEN)
                .build();
        OAuth2AccessToken accessToken = (OAuth2AccessToken) this.tokenGenerator.generate(tokenContext);

        // 6. 存储授权信息并返回认证结果
        OAuth2Authorization authorization = authorizationBuilder
                .token(accessToken, metadata -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, accessToken.getClaims()))
                .build();
        this.authorizationService.save(authorization);

        return new OAuth2AccessTokenAuthenticationToken(
                authToken.getRegisteredClient(), userAuthentication, accessToken);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return SsoOAuth2AuthorizationGrantAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

3. 注册自定义Provider到授权服务器

在授权服务器配置类中,将自定义的AuthenticationProvider注册进去:

@Configuration
public class AuthorizationServerConfig {

    // 基础授权服务器安全过滤链
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    // 客户端配置(示例用内存存储,生产建议用数据库)
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient ssoClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("sso-client")
                .clientSecret("{noop}sso-secret") // 生产用加密密码
                .authorizationGrantType(new AuthorizationGrantType(SsoOAuth2AuthorizationGrantAuthenticationToken.GRANT_TYPE))
                .scope("user_info")
                .build();
        return new InMemoryRegisteredClientRepository(ssoClient);
    }

    // 注册自定义AuthenticationProvider
    @Bean
    public OAuth2AuthorizationServerConfigurer authorizationServerConfigurer(
            SsoOAuth2TokenGrantAuthenticationProvider ssoProvider) {
        return new OAuth2AuthorizationServerConfigurer()
                .authenticationProvider(ssoProvider);
    }
}

二、向JWT添加自定义声明与权限

新版推荐使用OAuth2TokenCustomizer来扩展JWT声明,无需修改令牌生成器核心逻辑,直接在令牌编码阶段注入自定义信息:

@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
    return context -> {
        // 只处理Access Token(如果需要处理ID Token,可单独判断)
        if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
            Authentication principal = context.getPrincipal();
            UserInfo userInfo = (UserInfo) principal.getPrincipal();

            // 添加自定义用户信息声明
            context.getClaims()
                    .claim("real_name", userInfo.getRealName())
                    .claim("email", userInfo.getEmail())
                    .claim("roles", userInfo.getRoles());

            // 添加权限列表声明
            Collection<String> authorities = principal.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());
            context.getClaims().claim("authorities", authorities);
        }
    };
}

这个自定义器会被Spring Authorization Server自动识别,在生成JWT时自动调用,将自定义声明写入令牌。

关键说明

  • 旧版的AbstractTokenGranter逻辑被拆分到了AuthenticationProvider和OAuth2TokenGenerator中,自定义授权类型的核心是实现AuthenticationProvider处理认证请求。
  • 自定义JWT声明优先用OAuth2TokenCustomizer,它是官方推荐的扩展方式,侵入性更低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 21:55:21