Django会话cookie因多个并发请求丢失
我正在开发一个应用程序,客户端会不时地向服务器发送请求(我们暂时不讨论原因)。当服务器处理这些请求时,它会检查客户端是否已经登录,方法是使用 request.user.is_authenticated()
大致是这样的:
def handle_ping_request(request):
if request.user.is_authenticated():
# Do something...
else:
# Do Something else...
我注意到,有时候服务器会收到一个登录请求,紧接着又收到同一个用户的 ping 请求。此时,客户端已经成功登录,服务器的响应会返回一个新的会话 ID(对应已登录的用户),而我猜测旧的会话 ID(对应未登录的用户)会被删除。当服务器处理 ping 请求时,这个请求里包含的是旧的会话 ID。因此,ping 请求的响应会返回一个第三个会话 ID,而在客户端下一个请求时,客户端就会发现自己已经不再登录了。
我的登录代码大概是这样的:
if not request.user.is_authenticated():
user = auth.authenticate(...credentials...)
if user and user.is_active:
auth.login(request, user)
你有什么建议可以避免这个问题吗?最好是不需要客户端做什么。
谢谢。
2 个回答
你可以创建一个替代标准的 contrib.auth.login 方法,让它保持相同的会话 ID,而不是生成一个新的。这可以通过使用一个自定义的身份验证后端来实现,这个后端不会生成新的密钥,或者通过创建一个自定义的会话后端,重写 contrib.sessions.base 中的 cycle_key() 方法 来重复使用相同的密钥。
但是:想想看,重复使用相同的会话密钥可能会带来什么风险——根据这个系统的使用场景,你可能会让自己更容易受到会话劫持的攻击(也就是说,只有一个会话 ID 可以被窃取),还有可能出现缓存问题,导致缓存返回未授权页面的内容,而不是授权页面的内容,因为会话 ID 在技术上是相同的,缓存无法区分这两种情况,等等等等。
简而言之:这就是为什么默认情况下,它是这样设计的原因。
在服务器上处理这个问题可能会很麻烦,因为你需要建立一种信号系统,来判断当前的请求是否来自正在进行身份验证的客户端。我建议的办法是,简单地修改客户端的代码,让它在等待登录请求的回复时,不去发送请求。