Django 1.2会话丢失

5
我之前问过类似的问题,但我进行了更多的研究,这个版本应该有所不同。在单个Django视图中注册、验证和登录用户似乎是一些SO用户遇到的问题,并且还没有得到真正的解答。
问题在于,我在一个单独的Django视图中注册、验证和登录用户。对于大多数用户来说,这很好,但对于其他用户,他们随后的请求(他们在我的网站上点击链接)会返回匿名用户。某种方式,已登录用户失去了他们的会话并被重定向到我的站点上不需要身份验证的页面。
当他们通过纯登录视图(而不是注册+登录视图)登录时,会话数据保持完好。问题似乎确实与在单个视图中注册和登录有关。
请参见此帖子以了解相同的问题:https://stackoverflow.com/questions/1693726/problem-with-combined-authentication-login-view
有人建议这可能是线程问题。我也看到有人建议它涉及缓存会话数据的后端。

你认为这个错误实际上与什么有关吗?我无法重现这个错误,这真的很让我束手无策。

编辑-我应该注意到我正在使用默认的数据库支持会话。

这是我的注册/登录视图。

def splash_register(request):
  if request.session.get('beta'):

    if request.method=='POST':
        userform=MyUserCreationForm(request.POST)
        if userform.is_valid():
            #username of <30 char is required by Django User model.  I'm storing username as a hash of user email 

            user=userform.save(commit=False)
            user.username=hash(user.email)
            user.save()



            username=user.username
            password=str(userform.cleaned_data['password'])
            user=auth.authenticate(username=username, password=password)
            if user is not None:
                auth.login(request,user)
                request.session['first_visit']=True
                return HttpResponseRedirect("/")
            else:
                return HttpResponseRedirect('/splash/register/')
        else:
            userform=MyUserCreationForm(request.POST)
            return render_to_response("website/splash_register.html", {'userform':userform}, context_instance=RequestContext(request))
    return render_to_response("website/splash_register.html", context_instance=RequestContext(request))     
else:
    return HttpResponseRedirect('/splash/')        

嗨,詹姆斯,我正在使用mod_wsgi。 - Ben
我恳求有人能在这里帮助我... - Ben
@brendan 我认为主要问题在于你提到无法复制它?那你确定你能修复它吗? - James Khoury
也许在这个阶段直接解决它很困难,但我希望能有某种一般的起点。现在,我认为问题可能出在我的服务器配置(线程),我的会话后端(我现在只是使用默认数据库来存储会话数据),或者与那个“beta”会话变量相关的东西(尽管我不理解它)。从那里开始的任何线索都将非常有帮助。 - Ben
有意思,我不确定为什么我在那里使用了字符串函数。我毫无问题地将其删除了。 - Ben
显示剩余3条评论
3个回答

19

在这种情况下,您不必使用authenticate,实际上也并不需要。您只需要设置用户记录的后端即可。

因此,像这样做就可以了:

def splash_register(request):
  if request.session.get('beta'):

    if request.method=='POST':
        userform=MyUserCreationForm(request.POST)
        if userform.is_valid():
            #username of <30 char is required by Django User model.  I'm storing username as a hash of user email 

            user=userform.save(commit=False)
            user.username=hash(user.email)
            user.backend='django.contrib.auth.backends.ModelBackend'
            user.save()


            username=user.username
            password=str(userform.cleaned_data['password'])
            auth.login(request, user)
            request.session['first_visit']=True
            return HttpResponseRedirect("/")
        else:
            userform=MyUserCreationForm(request.POST)
            return render_to_response("website/splash_register.html", {'userform':userform}, context_instance=RequestContext(request))
    return render_to_response("website/splash_register.html", context_instance=RequestContext(request))     
else:
    return HttpResponseRedirect('/splash/')

更新

我在评论中提到过,但作为“答案”,解决方案是将以下内容添加到您的设置文件中:

SESSION_COOKIE_DOMAIN = 'yourdomain.com'

这将允许从 www.yourdomain.com 或者 yourdomain.com 访问网站的用户登录。


嗨Jordan,你提供的有关设置后端的信息非常有用。我很感激。我不确定它是否可以修复错误。这会产生一个少线程或其他有意义的影响吗? - Ben
这里有更多的信息。我正在使用apache2运行mod_wsgi。Mod_wsgi配置如下:服务器MPM:Preform,线程:no,分叉:yes(可变进程计数)。在我的日志文件中,我不断地在模块线程中引发KeyError,但被忽略了。我在网上查找了一些资料,似乎这可能是一个无害的问题,并不会导致更大的问题,但我想把它放在这里。 - Ben
感谢指出SESSION_COOKIE_DOMAIN设置,这解决了我的问题! - joshcartme

3

哦,天啊,我既松了一口气,又充满了自我厌恶。我不知道Cookie不能在www和非www域名之间传递。

我的一些用户来到了www,然后被重定向到非www,导致他们的会话结束。我现在正在设置mod_rewrite来解决这个问题。


1
如果这是您问题的原因,您需要将SESSION_COOKIE_DOMAIN设置为.yourdomain.com。请参见http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#session-cookie-domain - Jordan Reiter
感谢Jordan提供的帮助,以及其他所有的帮助。在这种情况下,指定赏金的礼仪是什么?经过数天的困惑,我真正回答了自己的问题。有任何线索吗? - Ben
从技术上讲,你的回答并不完全正确,因为Cookie在www和非www域之间是可以转移的。当然,我有偏见,但考虑到最终原因是由于会话数据丢失,因为Cookie没有绑定到域,而我的更新后的回答(和评论)解决了这个具体问题,如果你认为沿着这条路走是最佳解决方案,那么你可以把它归功于我(我肯定认为是这样!)。 - Jordan Reiter
好的,这对我来说很公平。谢谢Jordan,你帮了我很多。 - Ben

1

如果有人遇到类似的问题,我来分享一下我的经验。在当前视图中,request.user.is_authenticated()返回True,但是在重定向到同一主机的另一个页面后,request.user变成了匿名用户。我使用了会话,但事实证明这不是会话的问题。我自己编写了自定义身份验证后端,1.2文档说必须实现get_user(self, user_id),但我认为user_id(主键)没有什么特别之处,所以我将其实现为get_user(self, username)。但显然这就是问题的根源!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接