#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 через запрос. Я знаю, что пользователь аутентифицирован, потому что конечная точка для генерации токена защищена.