You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AdonisJS V6中结合Socket.IO验证用户登录及使用中间件?

问题:AdonisJS V6 + Socket.IO 验证用户登录状态与中间件使用
  • 如何在AdonisJS V6与Socket.IO中检查用户是否已登录?
  • 当前无法通过CSRF会话验证用户登录状态
  • 想确认Socket.IO中是否可以使用中间件

用户提供的代码

start/socket.ts

import adonisServer from '@adonisjs/core/services/server'
import { Server } from 'socket.io'
import UsersController from '#controllers/users_controller'

const io = new Server(adonisServer.getNodeServer())

io.on("connection", (socket) => {
  const socketController = new UsersController();
  socketController.handleMessage({ socket, io });
  socket.on("test", (args: any) => {
    socketController.handleTest({ socket, args });
  });
});

UsersController

import type { HttpContext } from '@adonisjs/core/http'
import { Role } from '@holoyan/adonisjs-permissions'
import User from '#models/user'
import { middleware } from '#start/kernel'
import { Request } from '@adonisjs/core/http'

let tttt = null;
export default class UsersController {
  async index({ }: HttpContext) { }
  async create({ request }: HttpContext) { }

  public handleMessage({ socket, io }: { socket: any, io: any }) {
    socket.emit("message", "world");
  }

  public async handleTest({ socket, args }: { socket: any, args: any }) {
    console.log(args);
    const handshake = socket.handshake
    console.log(handshake.auth.csrfToken);
  }
}

React前端代码

import { PageProps } from "~/Web/types";
import io from "socket.io-client";

export default function Dashboard({ csrf }: PageProps) {
  const socket = io({
    auth: {
      csrfToken: csrf,
    },
  });
  socket.on("message", (args: any) => {
    console.log(args);
  });
  socket.emit("test", csrf);

  console.log(csrf);
  return <h1>test</h1>;
}

解决方案

1. Socket.IO支持中间件,这是验证用户的正确方式

Socket.IO允许在连接建立前添加中间件,用于验证请求合法性,逻辑和AdonisJS的HTTP中间件一致。

2. 集成AdonisJS会话与CSRF验证到Socket.IO

修改start/socket.ts,添加认证中间件,利用AdonisJS的session和shield服务验证用户会话与CSRF:

import adonisServer from '@adonisjs/core/services/server'
import { Server } from 'socket.io'
import UsersController from '#controllers/users_controller'
import session from '@adonisjs/session/services/main'
import shield from '@adonisjs/shield/services/main'
import User from '#models/user'

const io = new Server(adonisServer.getNodeServer(), {
  cors: {
    origin: process.env.FRONTEND_URL, // 配置你的前端域名
    credentials: true // 允许携带Cookie
  }
})

// Socket.IO认证中间件
io.use(async (socket, next) => {
  try {
    // 从握手请求中获取Cookie
    const cookieHeader = socket.handshake.headers.cookie || ''
    // 初始化会话
    const sessionStore = await session.create()
    await sessionStore.initFromRequest({
      headers: { cookie: cookieHeader },
      method: 'GET',
      url: '/'
    })

    // 验证CSRF Token
    const csrfToken = socket.handshake.auth.csrfToken
    await shield.verifyCsrfToken(csrfToken, sessionStore)

    // 检查用户是否登录(从会话中获取用户ID)
    const userId = sessionStore.get('user_id')
    if (!userId) {
      throw new Error('未登录')
    }

    // 获取用户实例并挂载到socket对象
    const user = await User.findOrFail(userId)
    socket.user = user

    next()
  } catch (error) {
    next(new Error('认证失败: ' + error.message))
  }
})

io.on("connection", (socket) => {
  console.log('用户已连接:', socket.user.email)
  const socketController = new UsersController();
  socketController.handleMessage({ socket, io });
  socket.on("test", (args: any) => {
    socketController.handleTest({ socket, args });
  });
});

3. 在控制器中使用已验证的用户

修改UsersController的handleTest方法,直接从socket获取用户:

public async handleTest({ socket, args }: { socket: any, args: any }) {
  console.log('当前用户:', socket.user)
  console.log('收到参数:', args)
}

4. 前端注意事项

确保Socket.IO客户端携带Cookie,修改React代码:

import { PageProps } from "~/Web/types";
import io from "socket.io-client";

export default function Dashboard({ csrf }: PageProps) {
  const socket = io(process.env.NEXT_PUBLIC_API_URL, {
    auth: {
      csrfToken: csrf,
    },
    withCredentials: true // 必须开启,携带会话Cookie
  });
  
  socket.on("connect_error", (err) => {
    console.error('连接失败:', err.message)
  })

  socket.on("message", (args: any) => {
    console.log(args);
  });
  socket.emit("test", csrf);

  return <h1>test</h1>;
}

内容的提问来源于stack exchange,提问作者Ahmed Elkady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 09:40:59