безопасность веб-сокета micronaut

#websocket #micronaut

#веб-сокет #micronaut

Вопрос:

У меня есть следующий сервер websocket, определенный в micronaut:

 @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)
}
  

В ходе теста клиент правильно аутентифицирован, и все работает. Однако я не могу пройти аутентификацию в websocket в моем интерфейсном коде с помощью библиотеки сокетов rxjs. Я не смог найти никакой документации о том, как micronaut может обрабатывать безопасность websocket в целом. У вас есть какие-нибудь советы для меня?

Ответ №1:

В 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")
  

Ответ №2:

Для всех, кому интересно, после небольшого исследования websockets действительно поддерживают аутентификацию — происходит первоначальный HTTP-вызов, который приводит к ответу switching protocols , а затем открывается соединение с сокетом.

Идея состоит в том, чтобы аутентифицировать пользователя при этом начальном HTTP-вызове, передавая вашу аутентификацию в заголовке, как обычно. Проблема с этим, однако, заключается в том, что либо библиотеки интерфейса для websockets не поддерживают передачу этого заголовка при этом http-вызове, либо браузер этого не разрешает — я на самом деле не специалист по интерфейсу, но суть в этом.

В итоге я решил проблему, сгенерировав токен «одноразовый», который интерфейс должен сгенерировать через rest api, а затем передать его в websocket через запрос. Я знаю, что пользователь аутентифицирован, потому что конечная точка для генерации токена защищена.