В STOMP-протоколе авторизация тесно связана с этапом установления соединения и последующей подпиской на брокер сообщений. В STOMP.js контроль доступа реализуется через заголовки CONNECT, а также через серверную валидацию, которая может завершиться как отказом в соединении, так и асинхронной ошибкой после успешного подключения.
Ключевая особенность заключается в том, что ошибка авторизации не
всегда проявляется в момент вызова connect. В зависимости
от реализации брокера (Spring WebSocket, RabbitMQ STOMP plugin,
ActiveMQ) отказ может быть возвращён:
Авторизация в STOMP.js обычно реализуется через заголовки CONNECT:
client.connect(
{
Authorization: `Bearer ${token}`
},
onConnect,
onError
);
или в более новых версиях API:
const client = new Client({
brokerURL: "wss://example.com/ws",
connectHeaders: {
Authorization: `Bearer ${token}`
}
});
На уровне протокола STOMP эти заголовки становятся частью CONNECT frame и могут быть перехвачены сервером до создания сессии.
При использовании STOMP поверх WebSocket сервер может отклонить соединение ещё до установления канала связи. В этом случае STOMP.js не получает STOMP frame, а срабатывает обработчик WebSocket ошибки.
Типичные сценарии:
Обработка:
client.onWebSocketEr ror = (event) => {
console.error("WebSocket error:", event);
};
client.onStompEr ror = (frame) => {
console.error("STOMP error:", frame.headers["message"]);
};
Важно учитывать, что onStompError не будет вызван, если
соединение не дошло до STOMP-уровня.
После установления соединения сервер может отправить специальный ERROR frame:
ERROR
message: Authentication failed
content-type: text/plain
Access denied
STOMP.js обрабатывает это через onStompError:
const client = new Client({
onStompError: (frame) => {
console.error("Broker error:", frame.headers["message"]);
console.error("Details:", frame.body);
}
});
В этой модели соединение считается установленным, но сервер завершает сессию принудительно.
Некоторые брокеры не отправляют ERROR frame, а сразу закрывают соединение. В этом случае возникает событие WebSocket close.
client.onWebSocketCl ose = (event) => {
console.warn("Connection closed:", event.code, event.reason);
};
Коды закрытия:
Даже при успешном CONNECT авторизация может проверяться на уровне destination.
Пример: доступ к /topic/admin разрешён только
определённой роли.
В этом случае:
Пример обработки:
client.subscribe("/topic/admin", (message) => {
console.log(message.body);
});
Если брокер возвращает ошибку, она может прийти как отдельный ERROR frame или как системное сообщение в error destination.
Корректная обработка авторизации строится на трёх уровнях:
Отвечает за транспортное соединение.
onWebSocketError
onWebSocketClose
Основная задача — фиксация проблем handshake и сетевых сбоев.
Отвечает за протокол и брокер.
onStompError
Обрабатывает:
Отвечает за бизнес-логику доступа.
Сюда относятся:
При долгоживущих соединениях токен может устаревать. Сервер при этом:
Практика обработки:
onStompError: (frame) => {
if (frame.headers["message"] === "Token expired") {
refreshToken();
}
}
Если токен недействителен, сервер часто завершает соединение сразу.
Характер поведения:
Сценарий RBAC:
Поведение:
const state = {
connected: false,
lastError: null
};
client.onConn ect = () => {
state.connected = true;
};
client.onStompEr ror = (frame) => {
state.lastError = frame;
state.connected = false;
};
client.onWebSocketCl ose = () => {
state.connected = false;
};
STOMP frame может содержать полезные заголовки:
messageversioncontent-typeПример анализа:
onStompError: (frame) => {
const msg = frame.headers["message"];
if (msg.includes("unauthorized")) {
handleUnauthorized();
}
if (msg.includes("forbidden")) {
handleForbidden();
}
};
Перед каждым reconnect возможно обновление токена:
client.beforeConnect = () => {
client.connectHeaders.Authorization = `Bearer ${getToken()}`;
};
Это снижает вероятность повторных auth ошибок после реконнекта.
STOMP.js поддерживает автоматический reconnect, однако при ошибках авторизации он может приводить к циклу повторных неудачных подключений.
Типичная проблема:
Решение заключается в разделении типов ошибок:
onStompError: (frame) => {
const msg = frame.headers["message"];
if (msg.includes("unauthorized")) {
client.deactivate();
refreshToken();
}
};
Устойчивость к ошибкам авторизации достигается сочетанием:
Ключевой принцип заключается в том, что STOMP.js не предоставляет единого механизма auth error handling, и вся логика распределяется по слоям протокола и транспортного соединения.