具有自定义重定向适配器的 Django allauth 忽略“?下一个”参数

Django allauth with custom redirect Adapter ignoring "?next" parameter

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

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

这是我的自定义适配器(根据@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     

我必须修改我的自定义适配器,以便它在转到配置文件页面之前检查 'next' GET 参数(如果未指定 next 参数)。

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

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

首先,您的适配器原始代码(来自问题的 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 安全性的函数,导致它不被使用。解决方案是使用相对 urls 或编辑您的适配器以允许某些主机名:

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 这里的问题是您有一个 & 用于分隔查询字符串参数。尽管您说它可以通过将其替换为 ? 来工作,但理想情况下您还应该对它进行 url 编码,以便您的查询字符串变为 ?next=/%3Fpage%3D2? 替换为 %3F= 替换为 %3D).