中间件中的Django change request.path(通过url中的令牌进行身份验证)

中间件中的Django change request.path(通过url中的令牌进行身份验证),django,middleware,django-middleware,Django,Middleware,Django Middleware,亲爱的Stackoverflow的所有古生物 在Django 1.3中,我制作了一个process_请求中间件,它从url获取令牌,登录用户(如果正确),并从url中删除令牌。然而: 一) Django建议不要在中间件中访问POST/GET数据,我真的不知道为什么。。。这同样适用于request.path吗 二) 我想从URL中删除令牌,因此/album3/pic42/~53Cr3t70K3n/like/->/album3/pic42/like/。但是,更改request.path无效。此时将找

亲爱的Stackoverflow的所有古生物

在Django 1.3中,我制作了一个process_请求中间件,它从url获取令牌,登录用户(如果正确),并从url中删除令牌。然而:

一) Django建议不要在中间件中访问POST/GET数据,我真的不知道为什么。。。这同样适用于request.path吗

二) 我想从URL中删除令牌,因此
/album3/pic42/~53Cr3t70K3n/like/
->
/album3/pic42/like/
。但是,更改request.path无效。此时将找不到该页

  • 中间件处理正确(通过打印验证)

  • 直接输入
    /album3/pic42/like/
    确实有效

  • 错误(带有标记)显示
    请求URL:http://www.site.com/album3/pic42/like/

这有解决办法吗,还是我完全从错误的角度来处理这件事

提前谢谢

我刚刚意识到,要在客户端更改它,显然我需要重定向(为什么我没有想到…)。但是,如果能够在服务器端重写它,而不需要新的请求,例如访问个性化图像,则仍然很有用。


备注:如果需要更多细节,请跳过

我在一个网站上工作,该网站将向用户发送个性化的电子邮件。我希望用户能够单击电子邮件中的链接,并通过电子邮件链接中的令牌自动登录。这是对正常登录的补充。(我知道这不太安全,因为人们可能会转发电子邮件,但对我的网站来说已经足够了)。url的外观如下所示: /album3/pic42/~53Cr3t70K3n/like/(带剥离,Django完成)

我正在编写一个中间件来匹配这一点,并在适当的时候让用户登录,一个用于接受令牌作为有效凭据的身份验证后端和一个令牌模型


中间件进程请求功能: def过程_请求(自我,请求):


现在,它可以用于重定向,我也希望能够在内部执行此操作。

如果您不想搞砸,我有一个更好的解决方案:

  • 在你的url.py中创建一个规则,专门捕获使用令牌的访问

    将其放在
    urlpatterns
    的开头,以确保首先对其进行评估。这样做可以:

    (r'/~', 'my_app_name.my_redirect_view'),
    
  • 创建视图

    def my_redirect_view(request):
        #Compiled regular expressions work much faster
        beloved_tokens = re.compile(r'(.*)/~(.+?)/(.*)')
        result = beloved_tokens.search(request.path)
        try:
            (uidb36, token) = result.group(2).split('-', 2)
            path_end = result.group(3)
        # We use "try" to be sure that no one had
        # messed with our beloved tokens:
        except AttributeError: 
            raise Http404
        else:
            user = authenticate(uidb36 = uidb36, token = token)
            if user: 
                login(request, user)
                return HttpResponseRedirect('%s/%s' % (result.group(1), result.group(3)) + ('?' + '&'.join('='.join(item) for item in request.GET.items()) if request.GET else ''))
            else:
                raise Http404
    

  • 与访问GET/POST参数相比,IMO changing request.path更糟糕(如果可以称为bad),所以只需将令牌作为GET参数传递,并基于令牌登录,而不重定向或修改request.path


    我将令牌视为有效url的附加属性,因此中间件会承认这一点并使用该令牌执行某些操作,但url仍然由正确的视图处理,因此中间件在我看来非常符合逻辑。

    请提供中间件代码的相关部分。我已经添加了它,感谢您的评论当您说您希望在内部执行此操作时,您的意思是什么?当然,您可以添加一些额外的处理,以便从request.GET中删除令牌。但是整个概念仍然是一样的:我们不需要中间件来解决这个问题。使用url匹配是一个好主意,我没有想到这一点!(同时添加try-except是一个好主意)。但是有没有办法在这之后继续匹配去掉标记的url,因为它还需要一个不需要重定向的方法…@Mark,为什么不在url末尾添加一个标记呢?是否有一个特定的理由把它放在中间?你的意思是将它们与普通视图匹配,并且在视图开始时还是用中间件读取令牌?r“^album/”而不是r“^album/$”,我想如果我将类似r“^album2”的内容放在r“^album”之前(或者它与第一个匹配),这会起作用。无论如何,如果您使用中间件或普通视图,在url的末尾添加标记会更好。您可能应该使用token作为GET参数,如
    ?token=…
    ,并按照@Anurag的建议进行操作。我看不出有任何理由使用中间件。是的,我知道GET如何比request.path更适合于此,但它显然会给上载处理程序带来麻烦(我不知道以后是否需要)。但我想我至少可以使用GET进行重定向,在这种情况下,问题就不存在了@Ivan Kharlamov,但中间件使事情更易于处理,并且可以避免redirect@Mark,如果您正在修改上载处理程序,您可以在令牌中间件之前执行这些操作,一切都会好起来,csrf中间件也可以访问POSTparams@AnuragUniyal,您可能是对的,最好使用中间件。的确如此。
    def my_redirect_view(request):
        #Compiled regular expressions work much faster
        beloved_tokens = re.compile(r'(.*)/~(.+?)/(.*)')
        result = beloved_tokens.search(request.path)
        try:
            (uidb36, token) = result.group(2).split('-', 2)
            path_end = result.group(3)
        # We use "try" to be sure that no one had
        # messed with our beloved tokens:
        except AttributeError: 
            raise Http404
        else:
            user = authenticate(uidb36 = uidb36, token = token)
            if user: 
                login(request, user)
                return HttpResponseRedirect('%s/%s' % (result.group(1), result.group(3)) + ('?' + '&'.join('='.join(item) for item in request.GET.items()) if request.GET else ''))
            else:
                raise Http404