如何将@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,令牌总是空的。
2条答案
按热度按时间t9aqgxwy1#
我假设您已经从https://spring.io/blog/2020/06/17/getting-started-with-rsocket-spring-security开始
我能够使用与@Payload不同的类型为我的代码库实现此功能
第一个
uz75evzq2#
我正在使用Keycloak作为jwt Issuer。只需跟踪此git repo。唯一对我不起作用的是
解决上述问题的方法是使用以下两种方法之一
或直接使用
希望这对你有用,好好享受吧!