如何将 Django HTTP 登录会话与 Websocket 会话/Cookie 同步?

Posted

技术标签:

【中文标题】如何将 Django HTTP 登录会话与 Websocket 会话/Cookie 同步?【英文标题】:How to Sync Django HTTP Login Session with Websocket Session/Cookie? 【发布时间】:2019-08-06 13:40:40 【问题描述】:

我正在使用 Django DjangoChannelsGraphqlWs,它是 Django Channels 的石墨烯版本。 (https://github.com/datadvance/DjangoChannelsGraphqlWs) 它允许我使用 graphql 风格传输数据。我在我的变异模式上写了一个登录登录。

class Login(graphene.Mutation):
    class Arguments:
        email = graphene.String()
        password = graphene.String()

    ok = graphene.Boolean()
    user = graphene.Field(UserType)

    def mutate(root, info, email, password, **kwargs):
        ok = False
        user = authenticate(info.context, username=email, password=password)
        if user is not None:
            login(info.context, user)
            update_or_create_user_login_info(info=info)
            ok = True
            return Login(ok=ok, user=user)
        else:
            return Login(ok=ok)

我使用 Apollo-client 编写了我的客户端 Websocket,如下所示:

class WebSocketService 
    static instance = null;
    callbacks = ;

    static getInstance() 
        if (!WebSocketService.instance)
            WebSocketService.instance = new WebSocketService();
        return WebSocketService.instance;
    

    constructor() 
        this.socketRef = null;
        this.connect();
    

    connect() 
        const client = new SubscriptionClient(BASE_URL + '/graphql/', 
            reconnect: true,
        );
        const link = new WebSocketLink(client);
        const cache = new InMemoryCache();

        this.socketRef = new ApolloClient(
            link,
            cache,
        );
    

    query = (query, variables=, context=, fetchPolicy='no-cache', errorPolicy='all') =>
        this.socketRef.query(
            query: gql`$query`,
            variables,
            context,
            fetchPolicy,
            errorPolicy
        )

    mutate = (mutation, variables=, context=, fetchPolicy='no-cache', errorPolicy='all') =>
        this.socketRef.mutate(
            mutation: gql`$mutation`,
            variables,
            context,
            fetchPolicy,
            errorPolicy
        )


const WebSocketInstance = WebSocketService.getInstance();

export default WebSocketInstance;

最后,这是我的消费者。

class MyGraphqlWsConsumer(channels_graphql_ws.GraphqlWsConsumer):
    """Channels WebSocket consumer which provides GraphQL API."""
    schema = schema
    send_keepalive_every = 60

我尝试使用 WebSocketInstance 登录。但是,当我交出 info.context 和 authenticate(info.context, user) 参数时,Django 的登录功能会失败。它抛出错误说“types.SimpleNamespace'对象没有属性'META'”。在偶然发现错误后,我放弃了使用 websocket 登录,并决定只使用 axios 和普通的 http 请求。

但这是另一个问题。会话和 cookie 未同步。当我使用 axios 和正常的 http 请求时,登录本身运行良好,但 websocket 连接不反映登录的 session/cookies。

我发现反映更改需要一些时间,并且在断开和重新连接 websocket 后发生。

我应该如何同步登录信息?

【问题讨论】:

您至少可以链接您正在使用的通道石墨烯库吗? @Ken4scholars 我在帖子中添加了链接! github.com/datadvance/DjangoChannelsGraphqlWs @Beginner,你检查过 DjangoChannelsGraphqlWs 文档的the Authentication section 吗? @prokher 是的,我做到了。我仍在使用这个库。这是一个非常好的图书馆。我决定通过普通的 Django 登录功能登录用户,因为我想让用户的会话持续存在。在客户端,如果以前连接过 Websocket,我必须重新连接。如果我关闭并重新连接 Websocket,它工作得很好。感谢您回复一个老问题:) @prokher 哦,我最初考虑基于 JWT 的身份验证,但我发现许多批评者说 localstorage 不是保护令牌的理想场所。如果它不是本地存储,我不知道在哪里保存令牌。此外,除非我将令牌的有效性保存在某处,否则我无法撤销令牌,因此它与基于会话的身份验证相同。 Lke 会话,我每次验证令牌时都必须访问数据,尽管我目前使用 Redis 缓存后端进行会话而不是模型后端。当用户更改密码时,我需要撤销令牌。 【参考方案1】:

尝试覆盖 graphl_jwt

class ObtainJSONWebToken(graphql_jwt.JSONWebTokenMutation):
    user = graphene.Field(UserType)
    session = graphene.String()

    @classmethod
    def resolve(cls, root, info, **kwargs):
    user=info.context.user
    if user:
        login(info.context,user)
        session=info.context.session
        session.save()
    
        if session.session_key:
        #print(session.session_key)
        return cls(user=user,session=session.session_key)
        else:
        raise Exception('try it again')

突变

class Mutation(graphene.ObjectType):
    token_auth=ObtainJSONWebToken.Field()

【讨论】:

以上是关于如何将 Django HTTP 登录会话与 Websocket 会话/Cookie 同步?的主要内容,如果未能解决你的问题,请参考以下文章

Django auth:如果他的 IP 与原始 IP 不匹配(他登录的那个),如何禁止用户会话

Java:跟踪用户登录会话 - 会话 EJB 与 HTTPSession

JSF HTTP 会话登录

会话被 django-all auth 重置

Django - cookies 会话跟踪技术

Django + JSON Web 令牌 + 禁用基于会话的授权