Estoy trabajando en una gran aplicación de Django, la gran mayoría de las cuales requiere un inicio de sesión para acceder. Esto significa que en toda nuestra aplicación hemos rociado:
@login_required
def view(...):
Está bien y funciona muy bien siempre que recordemos agregarlo en todas partes . Lamentablemente, a veces lo olvidamos, y el fracaso a menudo no es tan evidente. Si el único enlace a una vista está en una página @login_required, entonces no es probable que notes que puedes llegar a esa vista sin iniciar sesión. Pero los malos pueden notarlo, lo cual es un problema.
Mi idea era revertir el sistema. En lugar de tener que escribir @login_required en todas partes, tendría algo como:
@public
def public_view(...):
Solo para las cosas públicas. Intenté implementar esto con algo de middleware y parecía que no podía hacerlo funcionar. Todo lo que probé interactuó mal con otros middleware que estamos usando, creo. A continuación, intenté escribir algo para recorrer los patrones de URL para comprobar que todo lo que no es @public estaba marcado como @login_required; al menos, obtendríamos un error rápido si olvidábamos algo. Pero luego no pude averiguar cómo saber si @login_required se había aplicado a una vista ...
Entonces, ¿cuál es la forma correcta de hacer esto? ¡Gracias por la ayuda!
Respuestas:
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:
Luego, en settings.py, enumere las URL base que desea proteger:
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 el esquema de autenticación cambia, tiene un lugar adonde ir para realizar cambios globales.fuente
@public
decorador, que establece el_public
atributo a la vista, y el middleware luego omite esas vistas. El decorador csrf_exempt de Django funciona de la misma maneraExiste una alternativa a poner un decorador en cada función de vista. También puede poner el
login_required()
decorador en elurls.py
archivo. 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,
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.
fuente
En Django 2.1, podemos decorar todos los métodos en una clase con:
ACTUALIZACIÓN: También he encontrado que lo siguiente funciona:
y establezca
LOGIN_URL = '/accounts/login/'
en su settings.pyfuente
Es difícil cambiar las suposiciones incorporadas en Django sin reelaborar la forma en que se entregan las URL para ver las funciones.
En lugar de perder el tiempo en el interior de Django, aquí hay una auditoría que puede usar. Simplemente verifique cada función de vista.
Ejecute esto y examine la salida para
def
s sin los decoradores adecuados.fuente
Aquí hay una solución de middleware para django 1.10+
Los middlewares deben escribirse de una manera nueva en django 1.10+ .
Código
Instalación
Agregar a MIDDLEWARE
MIDDLEWARE = [... '.middleware.RequireLoginMiddleware', # Requerir inicio de sesión]
Fuentes:
Esta respuesta de Daniel Naab
Tutorial de Django Middleware por Max Goodridge
Documentos de middleware de Django
fuente
__call__
, elprocess_view
gancho todavía se usa [editado]Inspirado por la respuesta de Ber, escribí un pequeño fragmento que reemplaza la
patterns
función, envolviendo todas las devoluciones de llamada de URL con ellogin_required
decorador. Esto funciona en Django 1.6.Su uso funciona así (la llamada a
list
es necesaria debido ayield
).fuente
Realmente no puedes ganar esto. Simplemente debe hacer una declaración de los requisitos de autorización. ¿En qué otro lugar pondría esta declaración excepto junto a la función de vista?
Considere reemplazar sus funciones de vista con objetos invocables.
Luego, convierte sus funciones de vista en subclases de
LoginViewFunction
.No guarda ninguna línea de código. Y no ayuda al problema de "nos olvidamos". Todo lo que puede hacer es examinar el código para asegurarse de que las funciones de vista sean objetos. De la clase adecuada.
Pero incluso entonces, nunca sabrá realmente que todas las funciones de visualización son correctas sin un conjunto de pruebas unitarias.
fuente
def
's. Puede escribir trivialmente un script muy corto para escanear todosdef
los módulos de vista y determinar si se olvidó un @login_required.urls.py
.Sería posible tener un único punto de partida para todos
urls
en una especie de inclusión y decorarlo usando estos paquetes https://github.com/vorujack/decorate_url .fuente
Hay una aplicación que proporciona una solución plug-and-play para esto:
https://github.com/mgrouchy/django-stronghold
fuente