简体   繁体   English

Express.js,如何将 jwt cookie 传递给 Socket.io?

[英]Express.js, how to pass jwt cookie to Socket.io?

I have a login route that eventually create a jwt cookie named access_token .我有一个登录路由,最终会创建一个名为access_token的 jwt cookie。 After the login the client will receive this cookie and will send it on every request.登录后,客户端将收到此 cookie,并将在每次请求时发送它。 However I didn't found a way to pass this cookie on to Socket.io.但是我没有找到将这个 cookie 传递给 Socket.io 的方法。

Server side login route :服务器端登录路径:

const login = async (req, res) => {
      const {email, password} = req.body
      const user = await UserModel.findOne({email})
      const isMatch = await user.checkPassword(password)
      if (isMatch) {
        const userToken = JwtService.createToken(user.id)
        return res.cookie("access_token", userToken, {
            httpOnly: true,
            secure: process.env.NODE_ENV === "production"
        }).status(200).json({user:user.toJSON(),message: 'login success'})

    }
 }

Socket :插座 :

this.io = new socketio.Server(expressServer, {cors: {origin: 'http://localhost:3000'}})
    this.io.use((socket,next)=>{
        console.log(socket.handshake.headers.cookie); // undefiend
        next()
    })

Client :客户 :

  this.socket = socketIOClient(process.env.SOCKET_BASE_URL, {auth: {userId}});

Server :服务器 :

         import express, {RequestHandler} from 'express';
        import http from 'http'
        import cookieParser from "cookie-parser"
        import cors from 'cors';
        import {router} from '@router';
        import dotenv from 'dotenv'
        import mongoose from 'mongoose';
        import {SocketService} from "@services";
        
        const expressApp = express();
        
        const port = process.env.PORT || 3001;
        dotenv.config()
        
        expressApp.use(cors({
            origin: true,
            credentials: true
        }));
        expressApp.use(express.json() as RequestHandler);
        expressApp.use(cookieParser());
        expressApp.use('/', router)
        
        const httpServer = http.createServer(expressApp);
        new SocketService(httpServer)
        
        httpServer.listen(port, async () => {
            console.log(`server is listening on ${port}`);
            try {
               await mongoose.connect('mongodb://guess-it-mongo-dev:27017/guess-it', {connectTimeoutMS: 1000});
               console.log('connected to mongo server')
            } catch (e) {
                console.log(e);
            }
        });

1. Solution 1.解决方案

Assuming that you have only one cookie which is your jwt , you could get it with the socket param like so :假设您只有一个 cookie,即您的jwt ,您可以使用socket参数获取它,如下所示:

const token = socket.handshake.headers.cookie.split("=")[1];

If you have many cookies, you need to use some cookie parser and give it the socket.handshake.headers.cookie to parse it, for example:如果你有很多 cookie,你需要使用一些 cookie 解析器并给它socket.handshake.headers.cookie来解析它,例如:

function getCookie(cName) {
   const name = cName + "=";
   const cDecoded = decodeURIComponent(socket.handshake.headers.cookie);
   const cArr = cDecoded.split(';');
   let res;
   cArr.forEach(val => {
      if (val.indexOf(name) === 0) res = val.substring(name.length);
      })
   return res;
}
const token = getCookie("jwt"); // if your token is called jwt.

2. Troubleshot 2. 故障排除

If the given solution is not working for you, make sure you are setting up your app and socket this way to have them as a single server (feel free to change the port):如果给定的解决方案不适合您,请确保您以这种方式设置应用程序和套接字以将它们作为单个服务器(随意更改端口):

const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);

server.listen(9000, () => {
   console.log("server runnig on port " + 9000);
});

And the client should be connecting like this (with the same port as the server) :并且客户端应该像这样连接(使用与服务器相同的端口):

import { io } from "socket.io-client";

io("http://localhost:9000/", {
      transports: ["websocket"],
    });

3. An use case 3. 一个用例

For example, in the code below, I am authenticating every connection with a middleware :例如,在下面的代码中,我使用中间件验证每个连接:

io.use((socket, next) => {
const token = socket.handshake.headers.cookie.split("=")[1];
if (token) {
  jwt.verify(token, process.env.SECRET, (err, decodedToken) => {
    if (err) {
      next(new Error("invalid"));
    } else {
      User.findById(decodedToken.id, function (err, user) {
        if (err) {
          next(new Error("invalid"));
        } else {
          next();
        }
      });
    }
  });
} else {
  next(new Error("invalid"));
}
});

//if authentication is ok, the code below will get executed 
io.on("connection", (socket) => {
  // do things
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM