I am trying to use Spring Boot RSocket with Security using JWT Tokens. It is giving me an Access Denied error with no other useful information to help debug with?
Access Denied.
ApplicationErrorException (0x201): Access Denied at app//io.rsocket.exceptions.Exceptions.from(Exceptions.java:76) at app//io.rsocket.core.RSocketRequester.handleFrame(RSocketRequester.java:261) at app//io.rsocket.core.RSocketRequester.handleIncomingFrames(RSocketRequester.java:211) at app//reactor.core.publisher.LambdaSubscriber.onNext(LambdaSubscriber.java:160) at app//io.rsocket.core.ClientServerInputMultiplexer$InternalDuplexConnection.onNext(ClientServerInputMultiplexer.java:248) at app//io.rsocket.core.ClientServerInputMultiplexer.onNext(ClientServerInputMultiplexer.java:129) at app//io.rsocket.core.ClientServerInputMultiplexer.onNext(ClientServerInputMultiplexer.java:48) at app//reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122) at app//reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:364) at app//reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:404) at app//reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:725) at app//reactor.netty.http.client.WebsocketClientOperations.onInboundNext(WebsocketClientOperations.java:161) at app//reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at app//io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at app//io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327) at app//io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at app//io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at app//io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at app//io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at app//io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at app//io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at app//io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722) at app//io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658) at app//io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584) at app//io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) at app//io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at app//io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at app//io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base@11.0.14/java.lang.Thread.run(Thread.java:834)
Security Configfile
@Configuration
@EnableRSocketSecurity
@EnableReactiveMethodSecurity
class SecurityConfig {
@Bean
fun authorization(rsocketSecurity: RSocketSecurity): PayloadSocketAcceptorInterceptor {
val security: RSocketSecurity =
rsocketSecurity.authorizePayload { authorize: RSocketSecurity.AuthorizePayloadsSpec ->
authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
}
.jwt { jwtSpec ->
jwtSpec.authenticationManager(jwtReactiveAuthenticationManager(jwtDecoder()))
}
return security.build()
}
@Bean
fun jwtDecoder(): ReactiveJwtDecoder {
return TokenUtils.jwtAccessTokenDecoder()
}
@Bean
fun jwtReactiveAuthenticationManager(decoder: ReactiveJwtDecoder): JwtReactiveAuthenticationManager {
val converter = JwtAuthenticationConverter()
val authoritiesConverter = JwtGrantedAuthoritiesConverter()
authoritiesConverter.setAuthorityPrefix("ROLE_")
converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter)
val manager = JwtReactiveAuthenticationManager(decoder)
manager.setJwtAuthenticationConverter(ReactiveJwtAuthenticationConverterAdapter(converter))
return manager
}
@Bean
fun rsocketMessageHandler() = RSocketMessageHandler() .apply {
argumentResolverConfigurer.addCustomResolver(AuthenticationPrincipalArgumentResolver())
routeMatcher = PathPatternRouteMatcher()
rSocketStrategies = rsocketStrategies()
}
@Bean
fun rsocketStrategies() = RSocketStrategies.builder()
.routeMatcher(PathPatternRouteMatcher())
.build()
}
Message Controllerfile
@MessageMapping("api.v1.messages")
@Controller
class MessageController {
@MessageMapping("stream")
suspend fun receive(
@Payload inboundMessages: Flow<String>,
@AuthenticationPrincipal jwt: String
) {
println("MessageController: jwt: $jwt")
println("MessageController: inbound message: " + inboundMessages.first())
}
}
Testing usingMessageControllerTestfile
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MessageControllerTest(
@Autowired val rsocketBuilder: RSocketRequester.Builder,
@LocalServerPort val serverPort: Int
) {
@ExperimentalTime
@ExperimentalCoroutinesApi
@Test
fun `test that messages API streams latest messages`() {
val admin = HelloUser(userId = "9527", password = "password", role = HelloRole.ADMIN)
val token: UserToken = TokenUtils.generateAccessToken(admin)!!
val authenticationMimeType: MimeType =
MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.string)
runBlocking {
val rSocketRequester = rsocketBuilder.websocket(URI("ws://localhost:${serverPort}/rsocket"))
launch {
rSocketRequester.route("api.v1.messages.stream")
.metadata(token.token!!, authenticationMimeType)
.dataWithType(flow {
emit(
"Hey from test class"
)
})
.retrieveFlow<Void>()
.collect()
}
}
}
}
I've add the rest of the code example I did to GitHub https://github.com/CJMobileApps/rsocket-jwt-security-example
1条答案
按热度按时间8nuwlpux1#
我想通了。RSocket目前有一个bug或者只是文档不好。JWTs
BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE
的MimeType说它被弃用了,要用MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.string)
代替,但是这不起作用。当传递标记时,继续使用/将
BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE
与标记字符串沿着使用。