mirror of
https://github.com/django/django.git
synced 2025-11-18 19:01:40 +00:00
Fixed #36717 -- Redirect authenticated users on admin login view to next URL.
Some checks are pending
Docs / spelling (push) Waiting to run
Docs / blacken-docs (push) Waiting to run
Docs / lint-docs (push) Waiting to run
Linters / flake8 (push) Waiting to run
Linters / isort (push) Waiting to run
Linters / black (push) Waiting to run
Tests / Windows, SQLite, Python 3.14 (push) Waiting to run
Tests / JavaScript tests (push) Waiting to run
Some checks are pending
Docs / spelling (push) Waiting to run
Docs / blacken-docs (push) Waiting to run
Docs / lint-docs (push) Waiting to run
Linters / flake8 (push) Waiting to run
Linters / isort (push) Waiting to run
Linters / black (push) Waiting to run
Tests / Windows, SQLite, Python 3.14 (push) Waiting to run
Tests / JavaScript tests (push) Waiting to run
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
66b5a6de78
commit
5401b125ab
5 changed files with 53 additions and 19 deletions
1
AUTHORS
1
AUTHORS
|
|
@ -159,6 +159,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Ben Slavin <benjamin.slavin@gmail.com>
|
||||
Ben Sturmfels <ben@sturm.com.au>
|
||||
Bendegúz Csirmaz <csirmazbendeguz@gmail.com>
|
||||
Benedict Etzel <developer@beheh.de>
|
||||
Berker Peksag <berker.peksag@gmail.com>
|
||||
Bernd Schlapsi
|
||||
Bernhard Essl <me@bernhardessl.com>
|
||||
|
|
|
|||
|
|
@ -416,29 +416,27 @@ class AdminSite:
|
|||
"""
|
||||
Display the login form for the given HttpRequest.
|
||||
"""
|
||||
if request.method == "GET" and self.has_permission(request):
|
||||
# Already logged-in, redirect to admin index
|
||||
index_path = reverse("admin:index", current_app=self.name)
|
||||
return HttpResponseRedirect(index_path)
|
||||
|
||||
# Since this module gets imported in the application's root package,
|
||||
# it cannot import models from other applications at the module level,
|
||||
# and django.contrib.admin.forms eventually imports User.
|
||||
from django.contrib.admin.forms import AdminAuthenticationForm
|
||||
from django.contrib.auth.views import LoginView
|
||||
|
||||
redirect_url = LoginView().get_redirect_url(request) or reverse(
|
||||
"admin:index", current_app=self.name
|
||||
)
|
||||
if request.method == "GET" and self.has_permission(request):
|
||||
# Already logged-in, redirect accordingly.
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
context = {
|
||||
**self.each_context(request),
|
||||
"title": _("Log in"),
|
||||
"subtitle": None,
|
||||
"app_path": request.get_full_path(),
|
||||
"username": request.user.get_username(),
|
||||
REDIRECT_FIELD_NAME: redirect_url,
|
||||
}
|
||||
if (
|
||||
REDIRECT_FIELD_NAME not in request.GET
|
||||
and REDIRECT_FIELD_NAME not in request.POST
|
||||
):
|
||||
context[REDIRECT_FIELD_NAME] = reverse("admin:index", current_app=self.name)
|
||||
context.update(extra_context or {})
|
||||
|
||||
defaults = {
|
||||
|
|
|
|||
|
|
@ -40,20 +40,28 @@ class RedirectURLMixin:
|
|||
def get_success_url(self):
|
||||
return self.get_redirect_url() or self.get_default_redirect_url()
|
||||
|
||||
def get_redirect_url(self):
|
||||
"""Return the user-originating redirect URL if it's safe."""
|
||||
redirect_to = self.request.POST.get(
|
||||
self.redirect_field_name, self.request.GET.get(self.redirect_field_name)
|
||||
def get_redirect_url(self, request=None):
|
||||
"""Return the user-originating redirect URL if it's safe.
|
||||
|
||||
Optionally takes a request argument, allowing use outside class-based
|
||||
views.
|
||||
"""
|
||||
if request is None:
|
||||
request = self.request
|
||||
redirect_to = request.POST.get(
|
||||
self.redirect_field_name, request.GET.get(self.redirect_field_name)
|
||||
)
|
||||
url_is_safe = url_has_allowed_host_and_scheme(
|
||||
url=redirect_to,
|
||||
allowed_hosts=self.get_success_url_allowed_hosts(),
|
||||
require_https=self.request.is_secure(),
|
||||
allowed_hosts=self.get_success_url_allowed_hosts(request),
|
||||
require_https=request.is_secure(),
|
||||
)
|
||||
return redirect_to if url_is_safe else ""
|
||||
|
||||
def get_success_url_allowed_hosts(self):
|
||||
return {self.request.get_host(), *self.success_url_allowed_hosts}
|
||||
def get_success_url_allowed_hosts(self, request=None):
|
||||
if request is None:
|
||||
request = self.request
|
||||
return {request.get_host(), *self.success_url_allowed_hosts}
|
||||
|
||||
def get_default_redirect_url(self):
|
||||
"""Return the default redirect URL."""
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ Minor features
|
|||
:mod:`django.contrib.admin`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The admin site login view now redirects authenticated users to the next URL,
|
||||
if available, instead of always redirecting to the admin index page.
|
||||
|
||||
:mod:`django.contrib.admindocs`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -2413,6 +2413,32 @@ class AdminViewPermissionsTest(TestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context[REDIRECT_FIELD_NAME], reverse("admin:index"))
|
||||
|
||||
def test_login_redirect_when_logged_in(self):
|
||||
self.client.force_login(self.superuser)
|
||||
response = self.client.get(reverse("admin:login"))
|
||||
self.assertRedirects(response, reverse("admin:index"))
|
||||
|
||||
def test_login_redirect_to_next_url_when_logged_in(self):
|
||||
self.client.force_login(self.superuser)
|
||||
next_url = reverse("admin:admin_views_article_add")
|
||||
response = self.client.get(
|
||||
reverse("admin:login"),
|
||||
query_params={REDIRECT_FIELD_NAME: next_url},
|
||||
)
|
||||
self.assertRedirects(response, next_url)
|
||||
|
||||
def test_login_redirect_unsafe_next_url_when_logged_in(self):
|
||||
self.client.force_login(self.superuser)
|
||||
response = self.client.get(
|
||||
reverse("admin:login"),
|
||||
query_params={
|
||||
REDIRECT_FIELD_NAME: "https://example.com/bad",
|
||||
},
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("admin:index"), fetch_redirect_response=False
|
||||
)
|
||||
|
||||
def test_login_has_permission(self):
|
||||
# Regular User should not be able to login.
|
||||
response = self.client.get(reverse("has_permission_admin:index"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue