Solución:
El middleware puede ser su mejor opción. He usado este fragmento de código en el pasado, modificado de un fragmento que se encuentra en otro lugar:
import re
from django.conf import settings
from django.contrib.auth.decorators import login_required
class RequireLoginMiddleware(object):
"""
Middleware component that wraps the login_required decorator around
matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
settings.py. For example:
------
LOGIN_REQUIRED_URLS = (
r'/topsecret/(.*)$',
)
LOGIN_REQUIRED_URLS_EXCEPTIONS = (
r'/topsecret/login(.*)$',
r'/topsecret/logout(.*)$',
)
------
LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
be a valid regex.
LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
define any exceptions (like login and logout URLs).
"""
def __init__(self):
self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)
def process_view(self, request, view_func, view_args, view_kwargs):
# No need to process URLs if user already logged in
if request.user.is_authenticated():
return None
# An exception match should immediately return None
for url in self.exceptions:
if url.match(request.path):
return None
# Requests matching a restricted URL pattern are returned
# wrapped with the login_required decorator
for url in self.required:
if url.match(request.path):
return login_required(view_func)(request, *view_args, **view_kwargs)
# Explicitly return None for all non-matching requests
return None
Luego, en settings.py, enumere las URL base que desea proteger:
LOGIN_REQUIRED_URLS = (
r'/private_stuff/(.*)$',
r'/login_required/(.*)$',
)
Siempre que su sitio siga las convenciones de URL para las páginas que requieren autenticación, este modelo funcionará. Si esto no es un ajuste uno a uno, puede optar por modificar el middleware para que se adapte más a sus circunstancias.
Lo que me gusta de este enfoque, además de eliminar la necesidad de ensuciar el código base con @login_required
decoradores – es que si cambia el esquema de autenticación, tiene un lugar adonde ir para realizar cambios globales.
Existe una alternativa a poner un decorador en cada función de vista. También puede poner el login_required()
decorador en el urls.py
expediente. Si bien esto sigue siendo una tarea manual, al menos lo tiene todo en un solo lugar, lo que facilita la auditoría.
p.ej,
from my_views import home_view urlpatterns = patterns('', # "Home": (r'^$', login_required(home_view), dict(template_name="my_site/home.html", items_per_page=20)), )
Tenga en cuenta que las funciones de vista se nombran y se importan directamente, no como cadenas.
También tenga en cuenta que esto funciona con cualquier objeto de vista invocable, incluidas las clases.
En Django 2.1, podemos decorar todos los métodos en una clase con:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
@method_decorator(login_required, name="dispatch")
class ProtectedView(TemplateView):
template_name="secret.html"
ACTUALIZAR:
También he encontrado que lo siguiente funciona:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class ProtectedView(LoginRequiredMixin, TemplateView):
template_name="secret.html"
y establecer LOGIN_URL = '/accounts/login/'
en tus settings.py