micronaut websocket安全

问题描述

我在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安全的文档。你对我有什么提示吗?

解决方法

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

@Singleton
class AccessTokenReader implements TokenReader {

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

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

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

在JavaScript中,它看起来像这样:

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

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

该想法是在初始HTTP调用中对用户进行身份验证-照常在标头中传递身份验证。但是,问题在于,要么Websocket的前端库不支持在该http调用上传递此标头,要么浏览器不允许它-我不是真正的前端人员,但这就是要旨。

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