具有自定义重定向适配器的 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
).
我正在使用 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
).