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

时间:2011-11-06 00:55:56

标签: django middleware django-middleware

Stackoverflow的亲爱的无所不在的生物,

在Django 1.3中我创建了一个process_request中间件,它从一个url获取一个令牌,记录用户(如果正确)并从url中删除令牌。但是:

I)Django建议不要访问中间件中的POST / GET数据,我不确定为什么这样......请问同样适用于request.path? https://docs.djangoproject.com/en/dev/topics/http/middleware/#process-view

II)我想从网址中删除令牌,因此/album3/pic42/~53Cr3t70K3n/like/ - > /album3/pic42/like/。但是更改request.path不起作用。

时将找不到该页面
  • 中间件确实处理正确(通过打印验证)

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

  • 错误(带令牌)显示Request URL: http://www.site.com/album3/pic42/like/

有没有解决这个问题,还是我完全从错误的角度接近这个?

提前致谢!

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


P.s。:如果需要更多细节,随意跳过

我正在开发一个(将)向用户发送个性化电子邮件的网站。我希望用户能够点击电子邮件中的链接,并通过电子邮件链接中的令牌自动登录。这是正常登录的补充。 (我知道它不太安全,因为人们可能转发电子邮件,但这对我的网站来说已经足够了)。网址看起来像这样: / album3 / pic42 / ~53Cr3t70K3n / like /(http://www.site.com被删除,Django就是这样做了)

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


中间件process_request函数:     def process_request(self,request):

    if '/~' in request.path:
        result = re.search('(.*)/~(.+?)/(.*)', request.path)
        (uidb36, token) = result.group(2).split('-', 2)
        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 ''))
    return None

现在它适用于重定向,我也希望能够在内部完成。

2 个答案:

答案 0 :(得分:2)

如果您不想陷入upload handlers,我会为您提供更好的解决方案:

  1. 在您的urls.py中创建规则以专门捕获带有令牌的访问

    将其放在urlpatterns的开头,以确保首先评估它。这样的事情会做:

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

    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
    

答案 1 :(得分:1)

与访问GET / POST参数相比,IMO更改request.path更糟糕(如果它可以被称为坏),所以只需将令牌作为GET参数传递并基于令牌登录,不要重定向或执行request.path修改< / p>

我将令牌视为有效网址的附加属性,因此中间件会确认并使用该令牌执行某些操作,但网址仍由正确的视图处理,因此对我来说中间件似乎非常符合逻辑。