如何将 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 不匹配(他登录的那个),如何禁止用户会话