首页 > 解决方案 > 如何将 Django HTTP 登录会话与 Websocket 会话/Cookie 同步?

问题描述

我正在使用 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 连接不反映登录的会话/cookies。

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

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

标签: djangowebsocketdjango-channelsgraphene-python

解决方案


尝试覆盖 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()

推荐阅读