繁体   English   中英

Flask-Socketio 与 Flask-Login 的 current_user 不同步

[英]Flask-Socketio out of sync with Flask-Login's current_user

Python==3.8.5
Flask==1.1.2
Flask-SocketIO=4.3.0 (also tried 4.3.1)
Flask_Login=0.4.1

我将 gevent 与 Gunicorn 一起使用

gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker w 1 wsgi:server

我已经使用 Flask-Login 几年了,大约一年来,我设法让它作为带有 React 前端的 RESTful 应用程序的身份验证机制。 我遇到的问题在于 Flask-socketio 的使用。 虽然我成功注销,但flask_socketio端点中的current_user仍然保持current_user对象有效,更奇怪的是当我用另一个用户重新登录时,全局Flask应用程序中的current_user反映了注销和新登录,但是 flask_socketio 中的 current_user 与更改失去同步。 我已经搜索了很长一段时间,我找到了 Flask_socketio 的作者 Miguel Grinberg 的一篇博客文章,他指出:

Flask 会话在 Socket.IO 连接时复制到 Socket.IO 会话。 在建立 Socket.IO 连接后对 Flask 路由中的会话所做的更改将无法在 Socket.IO 会话上访问。 在 Socket.IO 事件处理程序中对会话所做的更改将无法在 Flask 用户会话上访问。

Flask 登录支持:您可以毫无问题地在 Socket.IO 事件处理程序中引用 current_user。

的确,我可以从 socket.io 引用和访问 current_user,但它始终是初始值,并不能反映它在其生命周期中可能受到的更改。

我可以在 socket.io 上下文中以某种方式访问​​整个应用程序(包括常规 http 请求)中可访问的 current_user 吗?

这是一个常规的 http 示例:

@auth_bp.route('/current_user/<int:id>')
def user_is_authenticated(id):
    if id:
        if current_user.is_authenticated:
            if current_user.id == int(id):
                return {
                            "code": 200,
                            "authenticated": True,
                            "message":"User is logged-in", 
                            "user": user_schema.dump(current_user),
                        }, 200
    return {
                "code": 400,
                "authenticated": False,
                "message":"Either user id missing or you are not authenticated.", 
                "user": None
            }, 400

如果我从客户端点击上述端点,我会得到实际的current_user。 下面是用于相同目的的 socketio 端点:

@socket.on('getCurrentUser', namespace='/auth')
def user_is_authenticated(data):
    id = data.get('id')
    if id:
        if current_user.is_authenticated:
            if current_user.id == int(id):
                user = user_schema.dump(current_user)
                emit('currentUser', {'user': user, 'room': user.room}, room=user.room)
    #emit event here to sid

模拟身份验证操作

#login as Adam Clark

current_user across Flask now is {
    fullname: 'Adam Clark',
    other_fields: 'data'
}

current_user in socketio context also is {
    fullname: 'Adam Clark',
    other_fields: 'data'
}

# logout

current_user across Flask now is AnonymousUser

current_user in socketio context also is still {
    fullname: 'Adam Clark',
    other_fields: 'data'
}


# login as John Wild

current_user across Flask now is {
    fullname: 'John Wild',
    other_fields: 'data'
}

current_user in socketio context also is still {
    fullname: 'Adam Clark',
    other_fields: 'data'
}

两者结果之间的唯一区别是 http 一个(Flask 端点)反映了 current_user 的当前状态,而 socket.io 仅维护对象的初始状态。

在使用基于 cookie 的会话和 Socket.IO 时,这是一个不幸的限制。 问题是,如果 HTTP 路由对会话进行了更改(例如使用 Flask-Login 注销),则无法告诉 WebSocket 连接会话 cookie 已更改,因为 WebSocket 不支持 cookie在初始连接请求之外。

文档链接: https : //flask-socketio.readthedocs.io/en/latest/#access-to-flask-s-context-globals

如果您需要在 HTTP 和 WebSocket 端之间同步会话,请使用服务器端会话。 Flask-Session 扩展是一个不错的选择。

暂无
暂无

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

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