登录 Django 后重定向到 Next
Posted
技术标签:
【中文标题】登录 Django 后重定向到 Next【英文标题】:Redirect to Next after login in Django 【发布时间】:2016-11-20 17:35:54 【问题描述】:当用户访问需要登录的 url 时。视图装饰器重定向到登录页面。用户输入他的用户名和密码后,我如何将用户重定向到他试图访问的页面(“下一个”)?
Views.py
def login_view(request):
template = 'pos/login.html'
form = LoginForm
if request.method == 'POST':
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
messages.success(request, "You have logged in!")
return redirect('home')
else:
messages.warning(request, "Your account is disabled!")
return redirect('/login')
else:
messages.warning(request, "The username or password are not valid!")
return redirect('/login')
context = 'form': form
return render(request, template, context)
@login_required(redirect_field_name='next', login_url='/login')
def bar(request):
template = 'pos/bar.html'
drink = OrderItem.objects.filter(product__catgory__gt=1).order_by('-created')
context = 'drink': drink
return render(request, template, context)
登录.html
<form action="/login" id="login_form" method="post" class="form-signin">
% csrf_token %
form.as_p
<button class="btn btn-lg btn-primary btn-block" type="submit" value="login">Sign in</button>
<input type="hidden" name="next" value="next" />
</form>
url.py
url(r'^login', views.login_view, name='login'),
forms.py
class LoginForm(AuthenticationForm):
username = forms.CharField(label="Username", required=True, max_length=30,
widget=forms.TextInput(attrs=
'class': 'form-control',
'name': 'username'))
password = forms.CharField(label="Password", required=True, max_length=30,
widget=forms.PasswordInput(attrs=
'class': 'form-control',
'name': 'password'))
【问题讨论】:
见here。在您的操作旁边添加<form action="/login?next=request.path" id="login_form" method="post" class="form-signin">
。
【参考方案1】:
你可以试试:
return redirect(self.request.GET.get('next'))
【讨论】:
我相信这会奏效,但如果我需要“下一个”或“家”怎么办? return redirect(self.request.GET.get('next', 'home') if 'home' 是一个命名的 url。否则它会返回 redirect(self.request.GET.get ('下一个', '/home/') 这很好用。但是,它允许重定向到外部 url。对于许多网站来说,这将是一个安全问题。 是的,这被称为开放重定向,被许多人认为是一个安全漏洞。【参考方案2】:接受的答案不检查重定向到外部站点的下一个参数。对于许多应用程序来说,这将是一个安全问题。 Django 以django.utils.http.is_safe_url
函数的形式内置了该功能。可以这样使用:
from django.shortcuts import redirect
from django.utils.http import is_safe_url
from django.conf import settings
def redirect_after_login(request):
nxt = request.GET.get("next", None)
if nxt is None:
return redirect(settings.LOGIN_REDIRECT_URL)
elif not is_safe_url(
url=nxt,
allowed_hosts=request.get_host(),
require_https=request.is_secure()):
return redirect(settings.LOGIN_REDIRECT_URL)
else:
return redirect(nxt)
def my_login_view(request):
# TODO: Check if its ok to login.
# Then either safely redirect og go to default startpage.
return redirect_after_login(request)
【讨论】:
这仍然不安全。is_safe_url
有 been renamed in Django 3 (see last bullet)。除了使用新功能 url_has_allowed_host_and_scheme
之外,您还应该确保使用 urlencode
过滤器对您的 URL 进行编码。
@mlissner 非常感谢您提供的信息,安全性很难!你知道iri_to_uri
和urlencode
的区别吗?
我不知道,尽管我向 Django 安全人员提出了这个问题,他们推荐了 iri_to_uri 方法。不过,我们使用的是 urlencode,因为我相信它可以实现相同的效果。
@mlissner 我明白了。看起来contrib.auth
采用的方法是首先在原始值上使用resolve_url
。见github.com/django/django/blob/3.1.7/django/contrib/auth/…
嗯,它实际上并没有“证明”什么,所以我没有发布它。想象一下一个使用 auth 登录的小型 Django 应用程序。【参考方案3】:
您可以尝试在 accounts/login.html 模板中的提交按钮之前添加此输入字段
<input type="hidden" name="next" value=" request.GET.next "/>
【讨论】:
【参考方案4】:将next
传递给登录表单,然后在隐藏输入中将该值传递给view
的表单可能有点复杂。
也可以在此处使用django.core.cache
。
这样就不需要向表单传递任何额外的内容或为表单提供额外的输入字段。
def login_view(request):
if request.method == 'GET':
cache.set('next', request.GET.get('next', None))
if request.method == 'POST':
# do your checks here
login(request, user)
next_url = cache.get('next')
if next_url:
cache.delete('next')
return HttpResponseRedirect(next_url)
return render(request, 'account/login.html')
【讨论】:
这被称为开放重定向,被许多人认为是一个安全漏洞。【参考方案5】:这对我来说真的很好用:
from django.shortcuts import redirect
def login(request):
nxt = request.GET.get("next", None)
url = '/admin/login/'
if nxt is not None:
url += '?next=' + nxt
return redirect(url)
如果前一个 URL 包含下一个 - 调用“登录”URL 并将前一个“下一个”附加到它。 然后,当您登录时 - 您将继续访问之前打算进入的页面。
在我的项目中,我制作了以下适用于 Swagger 登录/注销的助手:
def _redirect(request, url):
nxt = request.GET.get("next", None)
if nxt is not None:
url += '?next=' + nxt
return redirect(url)
def login(request):
return _redirect(request, '/admin/login/')
def logout(request):
return _redirect(request, '/admin/logout/')
【讨论】:
【参考方案6】:path_redirect = request.get_full_path().split('?next=',1)
if '?next=' in request.get_full_path():# Redirecting After Login
return redirect(path_redirect[1])
else:
return redirect('index')
【讨论】:
https://example.com/?next=/some_page&some_other_parameter=1
将重定向到已损坏的https://example.com/some_page&some_other_parameter=1
。
欢迎来到 ***。虽然此代码可能会回答问题,但提供有关 如何 和/或 为什么 解决问题的附加上下文将提高答案的长期价值。以上是关于登录 Django 后重定向到 Next的主要内容,如果未能解决你的问题,请参考以下文章