micronaut websocket 安全

micronaut websocket security

我在 micronaut 中定义了以下 websocket 服务器:

@ServerWebSocket("/v1/ws/socket")
@Secured(SecurityRule.IS_AUTHENTICATED)
@RequiredArgsConstructor
@Slf4j
public class MyWebSocket {

    @OnOpen
    public void onOpenSocket(WebSocketSession session) {
        String agentRef = session.getUserPrincipal().get().getName();
        log.info("opened websocket for: {}", agentRef);
    }

    @OnClose
    public void onClose(CloseReason closeReason) {
        log.info("closed websocket websocket with reason: {}", closeReason);
    }

    @OnMessage
    public void onMessage(String message) {
        log.info("received message in websocket: {}", message);
    }

    @OnError
    public void onError(Throwable error) {
        log.error("an error occured in websocket", error);
    }

}

我的应用程序具有 JWT 令牌身份验证,在我的单元测试中,我可以毫无问题地连接到套接字:

@Inject
@Client("/")
RxWebSocketClient webSocketClient1


@Shared
def bearer = 'example jwt'


def "client can authenticate and connect to the websocket"() {
    given:
        def request = HttpRequest.GET("/v1/ws/").bearerAuth(bearer)
        def MyWebSocketClient client =
                webSocketClient1.connect(MyWebSocketClient, request)
                        .blockingFirst()
    expect:
        client.session.isOpen()

    cleanup:
        client.session.close(CloseReason.NORMAL)
}

在测试中,客户端已正确验证,一切正常。但是,我无法使用 rxjs 套接字库在我的前端代码中对 websocket 进行身份验证。我找不到任何关于 micronaut 一般如何处理 websocket 安全性的文档。你有什么建议吗?

对于任何感兴趣的人,经过一些研究后,websockets 确实支持身份验证 - 有一个初始 HTTP 调用导致响应 switching protocols,然后打开套接字连接。

我们的想法是在初始 HTTP 调用时对用户进行身份验证 - 像往常一样在 header 中传递您的身份验证。然而,这个问题是 websockets 的前端库不支持在那个 http 调用上传递这个 header 或者浏览器不允许它 - 我不是真正的前端人,但这就是它的要点。

我最终通过生成前端必须通过 rest api 生成的“一次性”令牌来解决它,然后通过查询将其传递给 websocket。我知道用户已通过身份验证,因为生成令牌的端点是安全的。

在 micronaut 中,您可以实现自己的 TokenReader 以从查询参数中获取令牌。

@Singleton
class AccessTokenReader implements TokenReader {

    @Override
    public Optional<String> findToken(HttpRequest<?> request) {
        return request.getParameters().get("access_token", String.class);
    }
}

如果 micronaut 在 header 中找不到令牌,它将使用您的实现。 您所要做的就是将令牌放入查询参数中:

http://localhost:8080/v1/ws?access_token=xxxxxxxxx

在 JavaScript 中看起来像这样:

new WebSocket("ws://localhost:8080/v1/ws?access_token=xxxxxxxxx")