Django 注册/登录不会将用户定向到 ?next=/my/url



Setup

我使用[django-allauth][1]作为用户帐户。

# urls.py
url(r'^login$', allauth.account.views.login, name="account_login"),
url(r'^join$', allauth.account.views.signup, name="account_signup"), 

.

# settings.py
LOGIN_REDIRECT_URL = '/me' 
LOGIN_URL = '/join'  # users sent here if they run into @login_required decorator
# To collect additional info if user signs up by email:
ACCOUNT_SIGNUP_FORM_CLASS = 'allauth.account.forms.WinnerSignupForm'

.

该自定义注册表单:

# account/forms.py
from .models import Winner, FriendCode
class WinnerSignupForm(forms.ModelForm):
"""
This is the additional custom form to accompany the default fields email/password (and maybe username)
"""
class Meta:
model = Winner
fields = ('author_display_name','signupcode',)
widgets = {'author_display_name':forms.TextInput(attrs={
'placeholder': _('Display Name'), # 'Display Name',
'autofocus': 'autofocus',
})
,
'signupcode': forms.TextInput(attrs={
'placeholder': _('Invite code (optional)'), 
'autofocus': 'autofocus'
})
}

def signup(self, request, user):
# custom code that performs some account setup for the user
# just runs a procedure; there's no "return" at end of this block

我不认为我的自定义WinnerSignupForm导致了这个问题,因为即使我禁用它,问题仍然存在(即,我从settings.py中注释掉了这一行:ACCOUNT_SIGNUP_FORM_CLASS = 'allauth.account.forms.WinnerSignupForm')


行为

0. 不带?next=/some/url参数:

感谢settings.pyLOGIN_REDIRECT_URL,如果我访问example.com/joinexample.com/login,我会结束example.com/me

那很好。

1.如果我已经登录,一切按预期工作:

A) 如果我访问https://example.com/login?next=/some/url, 我立即被转发到https://example.com/some/url(没有被要求登录,因为我已经登录了)。 我得出结论,/login 视图正确读取了next=/some/url参数。

B)同样,如果我访问https://example.com/join?next=/some/url,我会立即转发到https://example.com/some/url。 我的结论是/join 视图也正确读取了next=/some/url参数。

2.如果我通过社交帐户登录或注册,一切按预期工作

这使用allauth/socialaccount

注册或登录后,我会被转到https://example.com/some/url

但是,问题来了:

3.但是!如果我通过电子邮件登录,?next=/some/url 将被忽略:

A) 如果我访问https://example.com/login?next=/some/url,我首先被带到/login 页面。如果我通过电子邮件登录,我会被转发到https://example.com/me由于某种原因,?next=不会覆盖设置中的默认LOGIN_REDIRECT_URL。 (如果我通过Twitter登录,?next=参数被正确读取,我被带到https://example.com/some/url

B)同样,如果我访问https://example.com/join?next=/some/url,我首先被带到/join(注册)页面,通过电子邮件成功登录后,我被带到/me,即settings.py中定义的后备LOGIN_REDIRECT_URL

检查注册/登录表单中的 POST 数据,"next"参数正常:{"next": "/some/url", "username": "myusername", "password": "..."}


更多背景信息

摘自django-allauth

# allauth/account/views.py
from .utils import (get_next_redirect_url, complete_signup,
get_login_redirect_url, perform_login,
passthrough_next_redirect_url)
...
class SignupView(RedirectAuthenticatedUserMixin, CloseableSignupMixin,
AjaxCapableProcessFormViewMixin, FormView):
template_name = "account/signup.html"
form_class = SignupForm
redirect_field_name = "next"
success_url = None
def get_form_class(self):
return get_form_class(app_settings.FORMS, 'signup', self.form_class)
def get_success_url(self):
# Explicitly passed ?next= URL takes precedence
ret = (get_next_redirect_url(self.request,
self.redirect_field_name)
or self.success_url)
return ret
...

.

# allauth/account/utils.py
def get_next_redirect_url(request, redirect_field_name="next"):
"""
Returns the next URL to redirect to, if it was explicitly passed
via the request.
"""
redirect_to = request.GET.get(redirect_field_name)
if not is_safe_url(redirect_to):
redirect_to = None
return redirect_to
def get_login_redirect_url(request, url=None, redirect_field_name="next"):
redirect_url 
= (url
or get_next_redirect_url(request,
redirect_field_name=redirect_field_name)
or get_adapter().get_login_redirect_url(request))
return redirect_url
_user_display_callable = None
...

我很确定当我开箱即用地安装[django-allauth][1]时它最初是有效的。我一定以某种方式干预了这个?next=/some/url功能,尽管我不记得它最后一次工作是什么时候,也不记得我做了什么来搞砸事情。

有关故障排除的任何提示将不胜感激。

(在相关的情况下 - 也许设置未正确读取;ACCOUNT_LOGIN_ON_PASSWORD_RESET = True似乎忽略了settings.py,用户必须在重置密码后登录。

@Akshay,以下解决方法对我有用。

我在get_login_redirect_url子函数内添加了以下行到allauth/account/adapter.py

goto = request.POST.get('next', '')
if goto:
return goto

澄清一下,结果如下所示:

class DefaultAccountAdapter(object):
# no change to stash_verified_email, unstash_verified_email, etc.
# edit only get_login_redirect_url as follows
def get_login_redirect_url(self, request):
"""
Returns the default URL to redirect to after logging in.  Note
that URLs passed explicitly (e.g. by passing along a `next`
GET parameter) take precedence over the value returned here.
"""
assert request.user.is_authenticated()
url = getattr(settings, "LOGIN_REDIRECT_URLNAME", None)
if url:
warnings.warn("LOGIN_REDIRECT_URLNAME is deprecated, simply"
" use LOGIN_REDIRECT_URL with a URL name",
DeprecationWarning)
else:
url = settings.LOGIN_REDIRECT_URL
# Added 20170301 - look again for ?next parameter, as work-around fallback
goto = request.POST.get('next', '')
if goto:
return goto
print "found next url in adapter.py"
else:
print "no sign of next in adapter.py"
# end of work-around manually added bit
return resolve_url(url)
# leave remainder of fn untouched 
# get_logout_redirect_url, get_email_confirmation_redirect_url, etc.

我仍然不知道我最初是如何破坏此功能的,所以我不会将我的答案标记为接受/最佳答案。但是,它确实解决了我遇到的问题,所以我很高兴。希望这对其他人有用。

最新更新