You need to enable JavaScript to run this app. WebFlux项目如何在WebFilter中从OAuth2 JWT令牌提取accountId
优惠活动
大模型
产品
解决方案
定价
更多

WebFlux项目如何在WebFilter中从OAuth2 JWT令牌提取accountId

问题根因
  • 你写的校验逻辑没有接入响应式流:WebFlux是响应式编程模型,你定义的ReactiveSecurityContextHolder.getContext()、serverWebExchange.getPrincipal()这一系列操作只是声明了处理逻辑,没有和后续的过滤器链执行逻辑拼接,也没有触发订阅,所以这部分代码实际根本不会运行。
  • 过滤器执行顺序错误:如果你自定义的WebFilter注册顺序早于Spring Security的认证过滤器链,执行校验逻辑时Spring Security还没有完成JWT令牌解析和认证上下文填充,自然拿不到用户信息。
实现方案

你不需要新增额外的SecurityWebFilterChain,只需要在现有安全配置中插入自定义校验过滤器,放在OAuth2资源服务器认证过滤器之后即可,正确代码如下:

1. 改造过滤器逻辑

public class AccountIdCheckFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        // 此处根据你的实际URL结构提取路径中携带的accountId
        String clientAccountId = exchange.getRequest().getPath().value().split("/")[2];
        return exchange.getPrincipal()
                .map(Principal::getName)
                // 校验JWT中解析的accountId和路径携带的是否一致
                .filter(jwtAccountId -> jwtAccountId.equals(clientAccountId))
                .switchIfEmpty(Mono.error(new SystemException("401 ERROR")))
                // 校验通过后继续执行后续过滤器逻辑
                .then(chain.filter(exchange));
    }
}

如果你的accountId是存储在JWT自定义Claim中而非Principal的name字段,可以用以下方式提取:

return exchange.getPrincipal()
        .cast(JwtAuthenticationToken.class)
        .map(auth -> auth.getTokenAttributes().get("accountId").toString())
        .filter(jwtAccountId -> jwtAccountId.equals(clientAccountId))
        .switchIfEmpty(Mono.error(new SystemException("401 ERROR")))
        .then(chain.filter(exchange));

2. 调整安全配置,插入过滤器

修改你现有的SecurityWebFilterChain配置,将自定义过滤器放在OAuth2资源服务器认证过滤器之后,确保执行时认证信息已经填充完成:

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    http
            .authorizeExchange()
            .pathMatchers("/api/**").authenticated()
            .anyExchange().authenticated()
            .and()
            .exceptionHandling()
            .accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))
            .and()
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
    // 插入自定义校验过滤器,位置在OAuth2资源服务认证过滤器之后
    http.addFilterAfter(new AccountIdCheckFilter(), SecurityWebFiltersOrder.OAUTH2_RESOURCE_SERVER);
    return http.build();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 17:54:09