【问题标题】:Django allauth with custom redirect Adapter ignoring "?next" parameter带有自定义重定向适配器的 Django allauth 忽略“?next”参数
【发布时间】:2021-11-03 20:53:15
【问题描述】:

我正在使用 Django 3.2 和 django-allauth 0.44

我有一个自定义适配器,可以在登录时将用户重定向到他们的个人资料页面 - 但是,我还希望能够使用 ?next=/some/url/(例如 /accounts/login/?next=https://127.0.0.1:8000/&page=2),以便用户在存在时被重定向到该 url是GET 参数中的next 参数。

这是我的自定义适配器(根据@iklinac 的建议进行了修改):

class MyAccountAdapter(DefaultAccountAdapter):
    
    def get_next_redirect_url(self, request, redirect_field_name="next"):
        """
        Returns the next URL to redirect to, if it was explicitly passed
        via the request.
        """
        redirect_to = get_request_param(request, redirect_field_name)
        if not self.is_safe_url(redirect_to):
            redirect_to = None
        return redirect_to    


    def get_login_redirect_url(self, request, url=None, redirect_field_name="next", signup=False):
        ret = url
        if url and callable(url):
            # In order to be able to pass url getters around that depend
            # on e.g. the authenticated state.
            ret = url()
        if not ret:
            ret = self.get_next_redirect_url(request, redirect_field_name=redirect_field_name)
        if not ret:
            if signup:
                #ret = self.get_signup_redirect_url(request)
                return reverse('profile', kwargs={'username': request.user.username}) 
            else:
                ret = '/' # Go home ..
        return ret     

我不得不修改我的自定义适配器,以便它在进入配置文件页面之前检查“下一个”GET 参数(如果没有指定 next 参数)。

但是,我的代码中的逻辑以某种方式被忽略了(next=/some/url 参数仍然被忽略)。

如何在使用自定义适配器的同时将 ?next=/some/url 与 django-allauth 一起使用?

【问题讨论】:

  • @iklinac 谢谢。感谢您提供的链接,我已经更新了我的问题。
  • @HomunculusReticulli 看来您正在遵循我之前给您的解决方案,据我所知它应该可以工作。以下是一些调试信息:allauth.account.views.LoginView 在其form_valid 方法中调用allauth.account.forms.LoginFormlogin 方法,然后调用allauth.account.utils.perform_login,然后调用allauth.account.utils.get_login_redirect_url,最后调用适配器get_login_redirect_url。可能的问题是您没有为适配器设置 ACCOUNT_ADAPTER 设置,或者您正在使用一些自定义登录视图。
  • 这篇文章中适配器的初始版本也足够了(到next的重定向由allauth.account.utils.get_login_redirect_url处理。
  • @HomunculusReticulli 我会在一段时间内写一个答案。

标签: django django-authentication django-allauth


【解决方案1】:

首先,您的适配器原始代码(来自问题的revision 1)如下是正确的:

class MyAccountAdapter(DefaultAccountAdapter):
    def get_login_redirect_url(self, request):
        print(f"GET request dict is {request.GET}")
        return reverse('profile', kwargs={'username': request.user.username})

问题是你没有设置ACCOUNT_ADAPTER设置。

接下来,正如您所说,您的 url 看起来像 /accounts/login/?next=https://127.0.0.1:8000/&page=2,问题在于您的重定向 url 是带有主机名的绝对 url,但 allauth 将 allowed_hosts=None 传递给验证此 url 安全性的函数,导致它不被使用。解决方案是使用相对 URL 或编辑您的适配器以允许某些主机名:

class MyAccountAdapter(DefaultAccountAdapter):
    def get_login_redirect_url(self, request):
        print(f"GET request dict is {request.GET}")
        return reverse('profile', kwargs={'username': request.user.username})
    
    def is_safe_url(self, url):
        try:
            from django.utils.http import url_has_allowed_host_and_scheme
        except ImportError:
            from django.utils.http import (
                is_safe_url as url_has_allowed_host_and_scheme,
            )

        return url_has_allowed_host_and_scheme(url, allowed_hosts={'127.0.0.1:8000'}) # add any other hostname you might want to allow redirects to

接下来您的查询字符串如下:?next=/&page=2 这里的问题是您有一个 & 用于分隔查询字符串参数。尽管您说它可以通过将其替换为 ? 来工作,但理想情况下,您还应该对其进行 urlencode,以便您的查询字符串变为 ?next=/%3Fpage%3D2? 替换为 %3F= 替换为 %3D)。

【讨论】:

    猜你喜欢
    • 2014-06-09
    • 2021-09-19
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 2013-03-04
    • 2013-10-07
    相关资源
    最近更新 更多