spring-security 使用JWT的RSocket Java Spring @身份验证主体

carvr3hs  于 2022-11-11  发布在  Spring
关注(0)|答案(2)|浏览(209)

如何将@AuthenticationPrincipal与RSocket方法@AuthenticationPrincipal单一标记一起使用

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

我创建了一个RSocketSecurityConfiguration类:

@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;
}

完整的上壳控制器:

@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());
    }
}

完全连接控制器:

@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客户端:

@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,令牌总是空的。

t9aqgxwy

t9aqgxwy1#

我假设您已经从https://spring.io/blog/2020/06/17/getting-started-with-rsocket-spring-security开始
我能够使用与@Payload不同的类型为我的代码库实现此功能
第一个

uz75evzq

uz75evzq2#

我正在使用Keycloak作为jwt Issuer。只需跟踪此git repo。唯一对我不起作用的是

@CurrentUserProfile Mono<UserProfile> currentUserProfile

解决上述问题的方法是使用以下两种方法之一

@CurrentUserProfile Mono<Jwt> currentUserProfile

或直接使用

@AuthenticationPrincipal Jwt currentUserProfile

希望这对你有用,好好享受吧!

相关问题