【问题标题】:Socket.io - Refresh tokens before reconnectSocket.io - 在重新连接之前刷新令牌
【发布时间】:2022-04-25 23:14:07
【问题描述】:

我正在使用 Socket.io 创建一个 Electron 应用程序。当用户的计算机进入睡眠模式时,服务器会断开与客户端的连接并抛出错误“传输关闭”。当用户尝试重新连接时,我检查令牌是否仍然有效,如果不是,我刷新它们并尝试将它们发送到 socketIo 服务器。

我遇到的问题是,在“reconnect_attempt”上,socket.io 不会等到我刷新令牌以尝试重新连接,它会立即尝试使用旧令牌重新连接,这些令牌被服务器拒绝,这似乎也终止与阻止未来重新连接尝试的用户的连接。

这是我连接到服务器的代码的一部分

module.exports.connect = async (JWT) => {
    return new Promise( async resolve => {

        console.log("connecting to the server")

        const connectionOptions = {
            secure: true,
            query: {token: JWT},
            reconnectionDelay: 4000
        }

        let socket = await socketIo.connect(`${process.env.SERVER_URL}:${process.env.SERVER_PORT}`, connectionOptions);

        resolve(socket)
    })
}

这是我的 reconnect_attempt 代码

socket.on('reconnect_attempt', async () => {

        const getCurrentJWT = require("../../main").getCurrentJWT;

        let JWT = await getCurrentJWT(); //By the time this line returns, socket.io has already tried to reconnect

        if(JWT.success) { //if refreshed successfully
            console.log("Trying to submit new token......", JWT);

            socket.query.token = JWT.JWT;

        } else {
            console.log("Token not refreshed.")
        }
    });

这是我在服务器上的一部分

    io.use(async (socket, next) => {

  let token = socket.handshake.query.token;

  //and the instruction from here https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
  let tokenIsValid = await checkTokenValidity(token);

  if( tokenIsValid ) {
    next();
  } else {
    next(new Error('invalidToken'));
    console.log("Not valid token")
  }
})

【问题讨论】:

    标签: socket.io refresh-token


    【解决方案1】:

    在您的服务器中有以下内容。

    io.use( async function(socket, next) {
        let address = socket.handshake.address;
        run++; // 0 -> 1
    
        // Validate Token
        const token = socket.handshake.auth.token;
        if(token !== undefined){
            try{
                await tokenVerify(token).then((payload) => {
                    const serverTimestamp = Math.floor(Date.now() / 1000);
                    const clientTimestamp = payload.exp;
    
                    if(clientTimestamp > serverTimestamp){
                        console.log("Connection from: " + address + " was accepted");
                        console.log("Token [" + token + "] from: " + address + " was accepted");
                        next();
                    }else{
                        console.log("Connection from: " + address + " was rejected");
                        console.log("Token [" + token + "] from: " + address + " was rejected");
                        next(new Error("unauthorized"));
                    }
                });
            }catch (e) {
                console.log(e);
            }
    
        }
    })
    

    使用上面的代码,如果令牌无效,服务器将响应“unauthorized”。

    因此,在客户端,我们可以捕获该消息,如下所示。

    socket_io.on("connect_error", (err) => {
            if(err?.message === 'unauthorized'){
                var timeout = (socket_reconnection_attempts === 0 ? 5000 : 60000)
                console.log("Trying to reconnect in the next " + (timeout / 1000) + ' seconds')
                setTimeout(function (){
                    console.log('Trying to reconnect manually')
                    socket_reconnection_attempts++;
                    loadAuthToken().then(function (token) {
                        socket_io.auth.token = token;
                        socket_io.connect();
                    })
                }, timeout)
            }
        });
    

    使用上面的代码,只有当错误消息为“unauthorized”时,客户端才会尝试重新连接并刷新令牌。

    变量“socket_reconnection_attempts”是为了避免在短时间内发送大量的重新连接尝试。

    【讨论】:

      【解决方案2】:

      简而言之,您可以为此使用身份验证。

      连接时

      auth: {
          token: token 
      } 
      

      重新连接时

      socket.auth.token = "NEW_TOKEN";
      socket.connect();
      

      我可以为此共享套接字 io 实现,您可以根据需要对其进行修改。

      对于客户端,

      let unauthorized = false;
      let socket = io.connect('ws://localhost:8080', {
          transports: ["websocket"],
          auth: {
              token: GET_YOUR_TOKEN()
          }
      });
      socket.on("connect", () => {
          unauthorized = false;
      });
      socket.on('UNAUTHORIZED', () => {
          unauthorized = true;
      });
      socket.on("disconnect", (reason) => {
          if (reason === "io server disconnect") {
              if(unauthorized) {
                  socket.auth.token = token;
              } 
              socket.connect();
          }
      });
      socket.on('PING', ()=>{
          socket.emit('PONG', token);
      });
      

      服务器端

      io.on("connection", (socket) => {
          socket.on('PONG', function (token) {
              if (isValidToken(token) == false) {
                  socket.emit("UNAUTHORIZED");
                  socket.disconnect();
              }
          });
          setInterval(() => {
              socket.emit('PING');
          }, <YOUR-TIME>);
      });
      

      【讨论】:

        猜你喜欢
        • 2021-11-16
        • 2015-04-03
        • 2021-05-01
        • 2019-07-07
        • 1970-01-01
        • 2021-08-20
        • 2014-04-30
        • 1970-01-01
        • 2020-04-14
        相关资源
        最近更新 更多