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

OAuth2.0刷新访问令牌时的额外验证逻辑实现问询

解决方案

方案1:自定义OAuth2RefreshTokenAuthenticationProvider(推荐)

直接继承官方的OAuth2RefreshTokenAuthenticationProvider,重写其authenticate方法,在生成新访问令牌前插入用户校验逻辑。这种方式无需复制转换器代码,完全复用原有逻辑,维护性更强。

步骤1:实现自定义Provider

@Component
public class CustomRefreshTokenAuthProvider extends OAuth2RefreshTokenAuthenticationProvider {

    private final UserDetailsService userDetailsService;
    private final AuthenticationManager authenticationManager;

    // 注入依赖:刷新令牌服务、令牌生成器、用户详情服务、认证管理器
    public CustomRefreshTokenAuthProvider(OAuth2RefreshTokenService refreshTokenService,
                                          OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator,
                                          UserDetailsService userDetailsService,
                                          AuthenticationManager authenticationManager) {
        super(refreshTokenService, tokenGenerator);
        this.userDetailsService = userDetailsService;
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        OAuth2RefreshTokenAuthenticationToken refreshTokenAuth = 
            (OAuth2RefreshTokenAuthenticationToken) authentication;

        // 从刷新令牌中获取存储的用户认证信息
        OAuth2Authentication storedAuth = getRefreshTokenService().findById(refreshTokenAuth.getRefreshToken().getTokenValue())
                .map(OAuth2RefreshToken::getAuthentication)
                .orElseThrow(() -> new InvalidGrantException("无效的刷新令牌"));

        // 获取用户名并执行校验
        String username = storedAuth.getName();
        UserDetails user = userDetailsService.loadUserByUsername(username);

        // 调用认证管理器执行用户活跃状态、权限等额外检查
        Authentication userAuthentication = new UsernamePasswordAuthenticationToken(
                user, null, user.getAuthorities()
        );
        authenticationManager.authenticate(userAuthentication);

        // 校验通过后,继续执行父类逻辑生成新的访问令牌
        return super.authenticate(authentication);
    }
}

步骤2:替换默认Provider

根据你的Spring Security版本,将自定义Provider注册到授权服务器的端点配置中:

Spring Security OAuth2 Legacy(旧版)

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private CustomRefreshTokenAuthProvider customRefreshTokenAuthProvider;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 替换默认的刷新令牌认证Provider
        endpoints.authenticationProvider(customRefreshTokenAuthProvider);
        // 其他配置(如tokenStore、clientDetailsService等)
    }
}

Spring Security 6+ OAuth2 Authorization Server

@Bean
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .tokenEndpoint(tokenEndpoint -> 
                // 注册自定义Provider
                tokenEndpoint.authenticationProvider(customRefreshTokenAuthProvider)
            );

    return http.build();
}

方案2:利用OAuth2AuthenticationValidator(适用于Spring Security 5.6+)

如果你的项目使用Spring Security 5.6及以上版本,可以通过自定义OAuth2AuthenticationValidator,在刷新令牌的认证流程中添加用户校验逻辑。

步骤1:实现自定义Validator

@Component
public class UserActiveStatusValidator implements OAuth2AuthenticationValidator<OAuth2RefreshTokenAuthenticationToken> {

    private final UserDetailsService userDetailsService;
    private final AuthenticationManager authenticationManager;

    public UserActiveStatusValidator(UserDetailsService userDetailsService,
                                     AuthenticationManager authenticationManager) {
        this.userDetailsService = userDetailsService;
        this.authenticationManager = authenticationManager;
    }

    @Override
    public OAuth2AuthenticationValidatorResult validate(OAuth2RefreshTokenAuthenticationToken authentication) {
        // 从刷新令牌关联的认证信息中获取用户名
        OAuth2Authentication storedAuth = authentication.getRefreshToken().getAuthentication();
        String username = storedAuth.getName();
        UserDetails user = userDetailsService.loadUserByUsername(username);

        try {
            // 执行用户校验
            Authentication userAuth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            authenticationManager.authenticate(userAuth);
            return OAuth2AuthenticationValidatorResult.success();
        } catch (AuthenticationException e) {
            // 校验失败,返回错误信息
            return OAuth2AuthenticationValidatorResult.failure(
                    new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT, e.getMessage(), null)
            );
        }
    }
}

步骤2:注册Validator到授权服务器

@Bean
public OAuth2AuthorizationManager<OAuth2RefreshTokenAuthenticationToken> refreshTokenAuthManager(
        OAuth2RefreshTokenService refreshTokenService,
        List<OAuth2AuthenticationValidator<OAuth2RefreshTokenAuthenticationToken>> validators) {
    OAuth2RefreshTokenAuthenticationProvider provider = new OAuth2RefreshTokenAuthenticationProvider(
            refreshTokenService, null // 按需注入tokenGenerator
    );
    provider.setAuthenticationValidators(validators);
    return provider::authenticate;
}

关键说明

  • 方案1是最直接且维护性最好的方式,完全复用官方Provider的核心逻辑,仅扩展校验步骤。
  • 避免复制OAuth2RefreshTokenAuthenticationConverter的原因:官方转换器会随Spring Security版本迭代更新,复制代码会导致后续版本升级时出现兼容性问题,增加维护成本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:50:04