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

Spring Boot中RSocket客户端如何通过元数据正确传递JWT令牌

问题原因

令牌开头的异常字符不是传输过程追加的脏数据,是RSocket Bearer认证元数据编码规范自带的类型标识字节:AuthMetadataCodec.encodeBearerMetadata方法返回的ByteBuf第1位会固定写入Bearer认证对应的类型标记(固定值0x80),如果服务端直接把整段认证元数据的字节数组转成字符串读取,就会把这个标识位识别为乱码字符。
另外你当前的客户端写法存在内存泄漏隐患:encodeBearerMetadata返回的ByteBuf在加入复合元数据后没有手动释放,高并发场景下会触发Netty内存泄漏告警。

正确实现方案

客户端JWT元数据传递(Java + Spring Boot)

推荐优先使用Spring RSocket内置的拦截器统一注入JWT,不用手动操作ByteBuf,从根源避免编码错误:

@Configuration
public class RSocketClientConfig {
    @Bean
    public RSocketRequester rSocketRequester(RSocketStrategies strategies) {
        RSocketRequester.Builder builder = RSocketRequester.builder()
                .rsocketConnector(connector -> connector.interceptors(interceptorRegistry ->
                        interceptorRegistry.forRequester((requesterMono) -> requesterMono
                                .map(requester -> (RSocket) new RSocketProxy(requester) {
                                    @Override
                                    public Mono<Payload> requestResponse(Payload payload) {
                                        String jwt = TenantContext.getCurrentToken();
                                        CompositeByteBuf metadata = (CompositeByteBuf) payload.metadata();
                                        metadata.addComponent(true, BearerTokenMetadata.encode(ByteBufAllocator.DEFAULT, jwt).getMetadata());
                                        return super.requestResponse(payload);
                                    }
                                })
                ));
        return builder.tcp("服务端地址", 服务端端口, strategies);
    }
}

如果需要手动组装复合元数据,参考以下写法,注意临时缓冲区的释放:

CompositeByteBuf compositeMetadata = ByteBufAllocator.DEFAULT.compositeBuffer();
// 写入路由元数据
ByteBuf routingMetadata = TaggingMetadataCodec.createRoutingMetadata(
        ByteBufAllocator.DEFAULT,
        Collections.singletonList("目标接口路由")
).getContent();
CompositeMetadataCodec.encodeAndAddMetadata(compositeMetadata, ByteBufAllocator.DEFAULT,
        RoutingMetadata.ROUTING_METADATA_TYPE, routingMetadata);
routingMetadata.release();
// 写入Bearer认证元数据
ByteBuf authMetadata = AuthMetadataCodec.encodeBearerMetadata(
        ByteBufAllocator.DEFAULT,
        TenantContext.getCurrentToken().toCharArray()
);
CompositeMetadataCodec.encodeAndAddMetadata(compositeMetadata, ByteBufAllocator.DEFAULT,
        BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE, authMetadata);
authMetadata.release();

注意不要硬编码元数据MIME类型字符串,直接引用BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE常量,避免版本迭代时类型值不匹配导致解析失败。

服务端JWT解析

不要直接将认证元数据的字节数组转字符串,使用官方解码器读取,会自动跳过开头的类型标识字节:

@MessageMapping("目标接口路由")
public Mono<ResponseVO> handleRequest(Payload payload) {
    // 解码认证元数据,自动过滤类型标识字节,拿到纯净的JWT
    BearerTokenMetadata tokenMetadata = BearerTokenMetadata.decode(payload.metadata());
    String jwt = tokenMetadata.getToken();
    // 后续执行JWT校验、业务处理逻辑即可
    return Mono.just(new ResponseVO());
}

如果已经集成Spring Security做RSocket认证,直接配置JWT认证规则即可,不需要手动解析元数据:

@Configuration
@EnableRSocketSecurity
public class RSocketSecurityConfig {
    @Bean
    public PayloadSocketAcceptorInterceptor rsocketAuthInterceptor(RSocketSecurity security) {
        security
                .authorizePayload(authz -> authz
                        .anyRequest().authenticated()
                )
                .jwt(Customizer.withDefaults());
        return security.build();
    }
}
避坑要点
  • 禁止直接将AuthMetadataCodec.encodeBearerMetadata返回的ByteBuf转字符串作为令牌使用,必须通过配套的decode方法解析
  • 手动操作Netty ByteBuf时严格遵守引用计数规则,临时缓冲区使用完成后及时调用release()释放
  • 不要硬编码RSocket扩展协议的MIME类型、标识位数值,优先使用官方提供的常量,避免跨版本兼容问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:51:14