spring-security 无法向Spring RSocket服务器验证RSocketKotlin客户端(ktor)

hfwmuf9z  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(126)

我已经创建了一个Spring RSocket服务器来提供Kotlinktor应用程序的实时更新。没有身份验证,kotlin客户端就可以连接到流并接收更新。当我使用RSocket Spring Security配置服务器的基本身份验证时,我不能再让它在kotlin客户端工作了。
"Kotlin那边"
下面是我用来请求流的代码:

var flow = rSocket.requestStream(buildPayload {
    data(ByteArray(0))
    compositeMetadata {
        add(SimpleAuthMetadata("app", "xrOMMKj2jyaf4vH9RC6w"))
        add(RoutingMetadata("api.v1.messages.events.stream/qQYISR9xcmR8ZtVHNgg1lbYgSQcxafPqPW0ZbE0yaA6ham6n54"))
    }
})

flow.onEach {
    println(it.data.readText())
}.collect()

上面的代码抛出异常io.rsocket.Kotlin.RSocketError$Setup$Rejected:请求流时访问被拒绝
观察结果:在服务器端配置安全性后,我对客户端所做的唯一更改是将SimpleAuthMetadata添加到复合元数据中。没有太多关于它的文档,所以我不知道这是否正确,或者是否还有其他配置要做。
我能够使它在客户端工作的唯一方法是向它添加springrsocket依赖项。

  • RSocketRequester配置:*
@Configuration
class RsocketConfiguration {

    @Bean
    fun rSocketRequester(rsocketRequesterBuilder: RSocketRequester.Builder): RSocketRequester? {
        val authenticationMimeType: MimeType =
            MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.string)
        val credentials = UsernamePasswordMetadata("app", "xrOMMKj2jyaf4vH9RC6w")

        return rsocketRequesterBuilder
            .rsocketStrategies { builder -> builder.encoder(SimpleAuthenticationEncoder()) }
            .setupMetadata(credentials, authenticationMimeType)
            .connectWebSocket(URI.create("ws://localhost:8080/rsocket")).block()
    }
}
  • 流请求:*
scope.launch {
        rSocketRequester
        .route("api.v1.messages.events.stream/{userId}", "qQYISR9xcmR8ZtVHNgg1lbYgSQcxafPqPW0ZbE0yaA6ham6n54")
        .retrieveFlow<EventMessage>()
        .collect {
            println(it.webhookId)
        }
}

不幸的是,由于消费者(客户端)是一个ktor应用程序,我不能简单地添加spring依赖项。有没有办法使用为Kotlin提供的依赖项使其工作?

c9x0cxw0

c9x0cxw01#

看起来您在Spring服务器端的SETUP帧级别上进行了身份验证,这很好。您可以指示您的纯Kotlinrsocket客户端通过SETUP帧发送凭证:

val connector = RSocketConnector {
        connectionConfig {
            // mime types
            payloadMimeType = PayloadMimeType(
                data = WellKnownMimeType.ApplicationJson,
                metadata = WellKnownMimeType.MessageRSocketCompositeMetadata
            )
            // payload for setup frame
            setupPayload(
                Json.encodeToSetupPayload("client", "password")
            )
        }
    }

encodeToSetupPayload函数:

fun Json.encodeToSetupPayload(username: String, password: String): Payload = buildPayload {
val auth = SimpleAuthMetadata(username, password)
data(ByteReadPacket.Empty)
metadata(CompositeMetadata(auth))}

...您现在可以建立联机:

val rsocket = connector.connect(ClientTransport(ServerAddress(8080, TransportType.WS)))

相关问题