带有JWT的RSocket Java Spring @AuthenticationPrincipal [英] RSocket Java Spring @AuthenticationPrincipal with JWT

查看:164
本文介绍了带有JWT的RSocket Java Spring @AuthenticationPrincipal的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们如何将@AuthenticationPrincipal与RSocket方法@AuthenticationPrincipal Mono令牌一起使用

How can we use @AuthenticationPrincipal with a RSocket Method @AuthenticationPrincipal Mono token

    public Mono<String> uppercase(String s, @AuthenticationPrincipal Mono<JwtAuthenticationToken> token) { 
        //Token is always null 
        return Mono.just(s.toUpperCase());
    }

我创建了一个RSocketSecurityConfiguration类:

I created a RSocketSecurityConfiguration class:

@Configuration
@EnableRSocketSecurity
@EnableReactiveMethodSecurity
@Slf4j
public class RSocketSecurityConfiguration {

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuerUri;

    @Bean
    PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
        rsocket
                .authorizePayload(authorize ->
                        authorize
                                .anyRequest().authenticated()
                                .anyExchange().permitAll()
                )
                .jwt(jwtSpec -> {
                    jwtSpec.authenticationManager(jwtReactiveAuthenticationManager(reactiveJwtDecoder()));
                });
        return rsocket.build();
    }
   @Bean
ReactiveJwtDecoder reactiveJwtDecoder() {

    NimbusReactiveJwtDecoder decoder = (NimbusReactiveJwtDecoder)
            ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
    return decoder;
}

   @Bean
    public JwtReactiveAuthenticationManager jwtReactiveAuthenticationManager(ReactiveJwtDecoder reactiveJwtDecoder) {
        JwtReactiveAuthenticationManager jwtReactiveAuthenticationManager = new JwtReactiveAuthenticationManager(reactiveJwtDecoder);

        JwtAuthenticationConverter authenticationConverter = new JwtAuthenticationConverter();
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        authenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        jwtReactiveAuthenticationManager.setJwtAuthenticationConverter( new ReactiveJwtAuthenticationConverterAdapter(authenticationConverter));

        return jwtReactiveAuthenticationManager;
    }
@Bean
RSocketMessageHandler messageHandler(RSocketStrategies strategies) {
    RSocketMessageHandler mh = new RSocketMessageHandler();
    mh.getArgumentResolverConfigurer().addCustomResolver(new AuthenticationPrincipalArgumentResolver());
    mh.setRSocketStrategies(strategies);

    return mh;
}

完整的UpperCaseController:

Full UpperCaseController:

@Slf4j
@Controller
public class UpperCaseController {

    @MessageMapping("uppercase")
    public Mono<String> uppercase(String s, @AuthenticationPrincipal Mono<JwtAuthenticationToken> token) {
        JwtAuthenticationToken currentToken = token.block();
        if ( currentToken == null ) {
            log.info("token is null");
        }
        return Mono.just(s.toUpperCase());
    }
}

完整的ConnectController:

Full ConnectController:

@Slf4j
@Controller
public class ConnectController {

    @ConnectMapping("connect")
    void connectShellClientAndAskForTelemetry(RSocketRequester requester,
                                              @Payload String client) {

        requester.rsocket()
                .onClose()
                .doFirst(() -> {
                    // Add all new clients to a client list
                    log.info("Client: {} CONNECTED.", client);
                })
                .doOnError(error -> {
                    // Warn when channels are closed by clients
                    log.warn("Channel to client {} CLOSED", client);
                })
                .doFinally(consumer -> {
                    // Remove disconnected clients from the client list

                    log.info("Client {} DISCONNECTED", client);
                })
                .subscribe();
    }
}

RSocket客户端:

RSocket Client:

@Component
@Slf4j
public class RSocketClient {

    private static final MimeType SIMPLE_AUTH = MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
    MimeType BEARER_AUTH =
            MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());

    private static final String BEARER_TOKEN = "....";
    private final RSocketRequester requester;
    private RSocketStrategies rsocketStrategies;

    public RSocketClient(RSocketRequester.Builder requesterBuilder,
                         @Qualifier("rSocketStrategies") RSocketStrategies strategies) {
        this.rsocketStrategies = strategies;
        SocketAcceptor responder = RSocketMessageHandler.responder(rsocketStrategies, new RSocketClientHandler());
            requester = requesterBuilder
                .setupRoute("connect")
                .setupData("MyTestClient")
                                .setupMetadata(new BearerTokenMetadata(BEARER_TOKEN), BEARER_AUTH)
                .rsocketStrategies(builder ->
                        builder.encoder(new BearerTokenAuthenticationEncoder()))
                .rsocketConnector(connector -> connector.acceptor(responder))
                .connectTcp("localhost", 7000)
                .block();

        requester.rsocket()
                .onClose()
                .doOnError(error -> log.warn("Connection CLOSED"))
                .doFinally(consumer -> log.info("Client DISCONNECTED"))
                .subscribe();
    }
    public void uppercase() {
               String response = requester
                .route("uppercase")
                .metadata(BEARER_TOKEN, BEARER_AUTH)
                .data("Hello")
                .retrieveMono(String.class).block();
        log.info(response);
    }
}

对于Spring REST,我做过非常类似的事情,并且工作正常,但对于RSocket,令牌始终为空.

I have done something very similar for Spring REST and it works fine but for RSocket the token is always null.

推荐答案

我假设您已经开始使用

I assume you have started with https://spring.io/blog/2020/06/17/getting-started-with-rsocket-spring-security

我能够使用与@Payload不同的类型使它适用于我的代码库

I was able to get this working for my codebase using a different type than @Payload

  @ConnectMapping
  fun handle(requester: RSocketRequester, @AuthenticationPrincipal jwt: String) {
    logger.debug("connected $jwt")
  }

  @MessageMapping("runCommand")
  suspend fun runCommand(request: CommandRequest, rSocketRequester: RSocketRequester, @AuthenticationPrincipal jwt: String): Flow<CommandResponse> {
...
  }

这篇关于带有JWT的RSocket Java Spring @AuthenticationPrincipal的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆