from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model, login as auth_login from django.contrib.auth.forms import AuthenticationForm from django.contrib.sites.shortcuts import get_current_site from django.http import HttpResponseRedirect from django.shortcuts import resolve_url from django.utils.decorators import method_decorator from django.utils.http import is_safe_url from django.views.decorators.cache import never_cache from django.views.decorators.csrf import csrf_protect from django.views.decorators.debug import sensitive_post_parameters from django.views.generic.edit import FormView class SuccessURLAllowedHostsMixin: success_url_allowed_hosts = set() def get_success_url_allowed_hosts(self): return {self.request.get_host(), *self.success_url_allowed_hosts} class LoginView(SuccessURLAllowedHostsMixin, FormView): """ Display the login form and handle the login action. """ form_class = AuthenticationForm authentication_form = None redirect_field_name = REDIRECT_FIELD_NAME template_name = 'registration/login.html' redirect_authenticated_user = False extra_context = None @method_decorator(sensitive_post_parameters()) @method_decorator(csrf_protect) @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): if self.redirect_authenticated_user and self.request.user.is_authenticated: redirect_to = self.get_success_url() if redirect_to == self.request.path: raise ValueError( 'Redirection loop for authenticated user detected. Check that ' 'your LOGIN_REDIRECT_URL doesn\'t point to a login page.' ) return HttpResponseRedirect(redirect_to) return super().dispatch(request, *args, **kwargs) def get_success_url(self): url = self.get_redirect_url() return url or resolve_url(settings.LOGIN_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, '') ) url_is_safe = is_safe_url( url=redirect_to ) return redirect_to if url_is_safe else '' def get_form_class(self): return self.authentication_form or self.form_class def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs['request'] = self.request return kwargs def form_valid(self, form): """Security check complete. Log the user in.""" auth_login(self.request, form.get_user()) return HttpResponseRedirect(self.get_success_url()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) current_site = get_current_site(self.request) context.update({ self.redirect_field_name: self.get_redirect_url(), 'site': current_site, 'site_name': current_site.name, **(self.extra_context or {}) }) return context