如何在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
相关产品推荐
相关产品推荐

