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

如何构建Socket.io认证?Flask-SocketIO连接前身份验证问询

实现Flask-SocketIO连接前的Token身份验证

看起来你已经搭好了基础的登录流程——用PHP校验账号密码生成Token并存库,接下来要把这个Token和SocketIO的连接绑定起来做身份验证对吧?这个方案非常合理,刚好适配你多客户端(JS+Python)的需求,下面给你拆解具体的实现细节:

一、Flask-SocketIO服务端:连接时校验Token

核心思路是在客户端发起SocketIO连接的瞬间,拦截请求并校验Token的有效性,无效则直接断开连接。

1. 提取Token并校验

客户端可以通过两种方式传递Token,服务端都可以兼容处理,这里推荐用HTTP Headers的方式(更隐蔽安全):

from flask import request
from flask_socketio import SocketIO, disconnect
import your_db  # 替换成你实际的数据库操作模块

app = Flask(__name__)
# 根据你的跨域需求配置cors_allowed_origins,生产环境别用通配符*
socketio = SocketIO(app, cors_allowed_origins="http://your-client-domain")

@socketio.on('connect')
def handle_connection():
    # 方式1:从HTTP Headers提取Token(推荐)
    auth_header = request.headers.get('Authorization', '')
    if not auth_header.startswith('Bearer '):
        disconnect()
        return False
    token = auth_header.split('Bearer ')[1]

    # 方式2:从URL查询参数提取(适合调试或某些场景)
    # token = request.args.get('token', '')

    # 校验Token是否有效且未过期
    if not is_token_valid(token):
        disconnect()
        return False
    
    # 验证成功后,可以把用户信息绑定到当前连接上,后续事件直接用
    user = get_user_by_token(token)
    # 用request.sid关联用户,因为每个连接的sid是唯一的
    socketio.server.manager.save_session(request.sid, {'user_id': user['id'], 'username': user['username']})

def is_token_valid(token):
    # 数据库查询:检查Token存在且过期时间在当前时间之后
    # 示例伪代码,根据你的数据库类型调整(MySQL/PostgreSQL等)
    with your_db.cursor() as cursor:
        cursor.execute("SELECT id FROM user_tokens WHERE token = %s AND expires_at > NOW()", (token,))
        return cursor.fetchone() is not None

def get_user_by_token(token):
    # 根据Token获取关联的用户信息,方便后续业务使用
    with your_db.cursor(dictionary=True) as cursor:
        cursor.execute("""
            SELECT u.id, u.username 
            FROM user_tokens t 
            JOIN users u ON t.user_id = u.id 
            WHERE t.token = %s
        """, (token,))
        return cursor.fetchone()

2. 关键注意点

  • 验证失败一定要调用disconnect(),拒绝非法连接
  • 给Token设置合理的过期时间(比如1小时),PHP生成Token时就要把过期时间存入数据库
  • 可以用socketio.server.manager.save_session把用户信息存在连接会话里,后续处理消息事件时直接取出使用

二、JavaScript客户端:携带Token连接

PHP登录成功后,把返回的Token存在客户端(比如localStorage),然后连接SocketIO时带上:

// 从localStorage获取登录后保存的Token
const authToken = localStorage.getItem('user_auth_token');

// 用Headers方式携带Token连接
const socket = io('http://your-flask-server:5000', {
    extraHeaders: {
        'Authorization': `Bearer ${authToken}`
    }
});

// 监听连接错误,处理验证失败的情况
socket.on('connect_error', (err) => {
    console.error('连接失败:身份验证未通过', err);
    // 这里可以引导用户重新登录,比如跳转到登录页
    window.location.href = '/login';
});

// 连接成功后的逻辑
socket.on('connect', () => {
    console.log('Socket连接成功,已完成身份验证');
});

三、Python客户端:兼容Token验证

后续接入Python客户端时,用python-socketio库同样可以携带Token:

import socketio

# 创建客户端实例
sio = socketio.Client()
# 从登录接口获取的有效Token
auth_token = "your-valid-token-here"

# 用Headers方式携带Token连接
sio.connect(
    'http://your-flask-server:5000',
    headers={'Authorization': f'Bearer {auth_token}'}
)

# 监听连接错误
@sio.event
def connect_error(err):
    print(f"连接失败:身份验证错误 - {err}")
    # 处理重新登录逻辑

# 连接成功事件
@sio.event
def connect():
    print("Socket连接成功,身份验证通过")

# 断开连接事件
@sio.event
def disconnect():
    print("Socket连接已断开")

四、额外安全优化建议

  • Token刷新机制:当Token快过期时,客户端可以主动请求PHP服务生成新Token,避免用户频繁登录
  • HTTPS强制传输:生产环境必须用HTTPS,防止Token在网络传输中被窃取
  • Token失效处理:用户注销、修改密码或账号异常时,要立即从数据库删除对应的Token,防止被恶意复用

内容的提问来源于stack exchange,提问作者Lee Melbourne

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:05:43