socket.handshake.query
ermöglicht derzeit das Festlegen von Daten auf connect
, kann jedoch nicht durch Verweis aktualisiert werden, bevor reconnect
ausgelöst wurde. Dies führt zu Problemen beim Autorisieren einer Socket-Verbindung mit Aktualisierungstoken.
//client
io.connect("wss://socket.server.com", {
query : {
token:"something dynamic"
}
});
Wenn der Server neu gestartet wird und die Clients reconnect
, kann das Token bei der erneuten Autorisierung des Sockets veraltet sein.
//server
io.use(function(socket, next) {
var query = socket.handshake.query;
if(isValidToken(query.token)){
next();//will never fire if the token has been updated
}
});
Abfrage als function
zulassen:
io.connect("wss://socket.server.com", {
query : function(){
return {
token:"something dynamic"
}
}
});
Im aktuellen Socket-Konstruktor:
if (opts && opts.query) {
this.query = opts.query;
}
Kann wie folgt geändert werden:
if(opts && opts.query) {
this.query = typeof opts.query == 'function' && opts.query.call(this) || opts.query;
}
+1
Fix für Fehler #1086 sollte auch Ihr Problem lösen. Das Ändern der Abfrageoptionen nach erfolgreicher Verbindung funktionierte mit der älteren socket.io-client-Version, aber mit der aktuellen Version ging der Verweis auf das Abfrageobjekt verloren :(
@reeltimedoktor derzeit sollten Sie in der Lage sein, das query
Objekt beim reconnect_attempt
Ereignis zu aktualisieren:
socket.on('reconnect_attempt', function () {
socket.io.opts.query = { token: /* ... */ };
});
Die Lösung von @darrachequesne scheint bei mir nicht zu funktionieren :(
Ich verwende socket.io-client
Version 2.3.0
auf dem Client, mit einem Knotenserver mit socket.io
Version 2.3.0
.
Auf dem Client mache ich das:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken();
socket.io.opts.query = {
token: latestToken,
};
});
Und dann authentifiziert der Server das Token mit einer Middleware, die an io.use()
(die dann ausgelöst werden sollte, wenn der Socket eine Verbindung oder erneute Verbindung herstellt, afaik?).
Im Moment schlägt die Serverauthentifizierung beim erneuten Verbinden fehl und sagt, dass das Token abgelaufen ist - es scheint, dass das neue Token socket.io.opts.query.token
nicht richtig zugewiesen wurde - haben Sie eine Idee, warum?
Danke :)
Update: Anscheinend gibt es im Socket-Objekt eine Reihe verschiedener Stellen, an denen das Auth-Token gespeichert ist, zB socket.io.engine.query.token
, socket.io.engine.transport.query.token
. Diese werden nicht automatisch ausgefüllt, wenn Sie socket.io.opts.query.token
festlegen. Das Ändern dieser Werte hat jedoch immer noch keinen Einfluss auf das, was die Server „sehen“ – es sieht immer noch nur das alte Token.
Das Token scheint auch als URL-Parameter in einigen der URL-Felder im Socket-Objekt enthalten zu sein. Vielleicht müssen diese auch aktualisiert werden?
Nach der Untersuchung weiter, dass es scheint , die Token - Einstellung auf socket.io.opts.query.token
ausreichend ist , das Token für die erneute Authentifizierung ändern auf der Wiederverbindung - scheint etwas anderes das Problem für meine Anwendung zu sein, vielleicht etwas mit Feuerbasis Auth - Token Generation zu tun. Für alle anderen, die darauf stoßen , @darrachequesne !
Ok, ich denke, ich habe es behoben - Sie müssen sicherstellen, dass Sie das neue Token synchron im Callback "reconnect_attempt" erhalten, dh tun Sie dies nicht:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken(); // won't work
socket.io.opts.query = {
token: latestToken,
};
});
Es scheint, als ob die serverseitige Authentifizierung durchgeführt wurde, bevor das neue Token festgelegt wurde. Wenn Sie das Token synchron abrufen (indem Sie es einige Zeit zuvor abrufen und speichern und dann einfach im Listener-Callback abrufen), erhält der Server das neue Authentifizierungstoken rechtzeitig für die Wiederverbindungsauthentifizierung.
mit "socket.io-client": "3.0.4"
erhalte ich einen TS2341: Property 'opts' is private and only accessible within class 'Manager'.
Fehler. Ich verwende "typescript": "4.1.3"
Ok, ich denke, ich habe es behoben - Sie müssen sicherstellen, dass Sie das neue Token _synchron_ im Callback 'reconnect_attempt' erhalten, dh tun Sie dies nicht:
socket.on('reconnect_attempt', async () => { const newToken = await getNewToken(); // won't work socket.io.opts.query = { token: latestToken, }; });
Es scheint, als ob die serverseitige Authentifizierung durchgeführt wurde, bevor das neue Token festgelegt wurde. Wenn Sie das Token synchron abrufen (indem Sie es einige Zeit zuvor abrufen und speichern und dann einfach im Listener-Callback abrufen), erhält der Server das neue Authentifizierungstoken rechtzeitig für die Wiederverbindungsauthentifizierung.
Wir haben ein ähnliches Problem. Aber meine aktuelle Problemumgehung besteht darin, disconnect
von der Serverseite aus zu verwenden, wenn die Authentifizierung fehlschlägt. Beim Empfang des disconnect
Ereignisses auf dem Client rekonstruieren wir die Abfrage/den Header mit dem asynchronen Promise-Aufruf. Wenn es das Ereignis reconnecting
, hat es bereits den neuen Wert in der Abfrage/im Header.
Für zukünftige Leser:
Das Verhalten der Option query
in Socket.IO v2 ist etwas seltsam, da sie in beiden verwendet wird:
Ich bin mir also nicht sicher, wie wir das abwärtskompatibel beheben könnten...
Bitte beachten Sie, dass dies in Socket.IO v3 behoben ist, da Sie jetzt die Option auth
:
// plain object
const socket = io({
auth: {
token: "abc"
}
});
// or with a function
const socket = io({
auth: (cb) => {
cb({
token: "abc"
});
}
});
Es sollte auch mit einer async
Funktion funktionieren:
const socket = io({
auth: async (cb) => {
cb({
token: "abc"
});
}
});
Siehe auch:
Hilfreichster Kommentar
@reeltimedoktor derzeit sollten Sie in der Lage sein, das
query
Objekt beimreconnect_attempt
Ereignis zu aktualisieren: