Aspectos destacados de Django: Modelos de usuario y autenticación (Parte 1)

Publicado: 2022-03-10
Resumen rápido ↬ Una de las principales razones para desarrollar un sitio dinámico es autenticar a los usuarios y restringir el contenido. Django proporciona un poderoso modelo de usuario listo para usar, y en este artículo, veremos la mejor manera de proporcionar flujos de autenticación de usuario seguros e intuitivos.

Hay dos tipos de sitios web: estáticos y dinámicos. Django es un marco para desarrollar sitios web dinámicos. Si bien un sitio web estático es aquel que únicamente presenta información, no hay interacción (más allá de las solicitudes de página simples) que se registra en un servidor. En un sitio web estático, el servidor envía HTML, CSS y JavaScript a un cliente y eso es todo. Más capacidades requieren un sitio web dinámico, donde el servidor almacene información y responda a la interacción del usuario más allá de solo servir páginas. Una de las principales razones para desarrollar un sitio dinámico es autenticar a los usuarios y restringir el contenido.

Escribir, implementar y administrar un sitio web estático es mucho más fácil, económico y seguro que un sitio dinámico. Por lo tanto, solo debe crear un sitio web dinámico si las capacidades adicionales del paradigma dinámico son necesarias para su proyecto. Django simplifica y agiliza el proceso de creación de un sitio dinámico con sus componentes integrados. Como uno de los componentes principales de una aplicación web dinámica, es tentador reinventar el objeto "cuenta de usuario", como la rueda, pero la forma estándar es apropiada para la mayoría de los usos. Django proporciona un poderoso modelo de usuario listo para usar, y en este artículo, veremos la mejor manera de proporcionar flujos de autenticación de usuario seguros e intuitivos.

Otras partes de la serie:

  • Aspectos destacados de Django: creación de plantillas de líneas de guardado (parte 2)
  • Aspectos destacados de Django: modelos, administración y aprovechamiento de la base de datos relacional (parte 3)
  • Aspectos destacados de Django: disputa de activos estáticos y archivos multimedia (Parte 4)

Preparándose

Si desea crear su propia aplicación Django para experimentar con los conceptos de este artículo, puede crear un directorio (y preferiblemente un entorno virtual) y luego ejecutar los siguientes comandos:

 pip install django django-admin startproject PROJECTNAME cd PROJECTNAME python manage.py startapp APPNAME python manage.py migrate python manage.py runserver

Si está buscando un tutorial para crear su primer proyecto de Django, el sitio web de Django ofrece uno excelente. En este artículo, no estamos usando un proyecto de ejemplo, pero los conceptos discutidos se aplicarán a casi todas las aplicaciones de Django.

¡Más después del salto! Continúe leyendo a continuación ↓

Modelo de usuario estándar

Fundamentalmente, el concepto de cuenta de usuario existe por dos razones: control de acceso y estado personalizado de la aplicación. El control de acceso es la idea de que los recursos en un sistema solo están disponibles para algunos usuarios. El estado personalizado depende en gran medida del propósito de la aplicación, pero puede incluir configuraciones, datos o cualquier otro registro específico de un usuario individual. El modelo de User de Django proporciona enfoques sensibles para ambos casos de uso.

Inicialmente, hay dos tipos de usuarios en una aplicación Django: cuentas de superusuario y usuarios regulares. Los superusuarios tienen todos los atributos y privilegios de las cuentas regulares, pero también tienen acceso al panel de administración de Django, una poderosa aplicación que exploraremos en detalle en un artículo futuro. Básicamente, los superusuarios pueden crear, editar o eliminar cualquier dato en la aplicación, incluidas otras cuentas de usuario.

Fundamentalmente, el concepto de cuenta de usuario existe por dos razones: control de acceso y estado personalizado de la aplicación.

Para crear un superusuario en su propia aplicación Django, ejecute:

 python manage.py createsuperuser

El otro beneficio de una cuenta de usuario es almacenar datos personalizados en la base de datos. De forma predeterminada, Django solo requiere un nombre de usuario y una contraseña, pero proporciona campos opcionales para que los usuarios ingresen su nombre, apellido y dirección de correo electrónico. Puede leer una referencia completa del modelo en el sitio web de Django. Discutiremos la extensión de este modelo a continuación.

Seguridad y Confiabilidad

Django incluye un importante middleware de gestión de contraseñas con el modelo de usuario. Se requiere que las contraseñas de los usuarios tengan al menos 8 caracteres, no enteramente números, no coincidan demasiado con el nombre de usuario y no estén en una lista de las 20,000 contraseñas más comunes. Los formularios bursátiles de Django validan estos requisitos. Cuando se envía una contraseña al servidor, se cifra antes de almacenarla, de forma predeterminada, utilizando el algoritmo PBKDF2 con un hash SHA256. En general, el sistema de contraseña predeterminado proporciona una seguridad sólida sin ningún esfuerzo por parte del desarrollador. A menos que tenga experiencia específica y una razón convincente para cambiar la forma en que se manejan las contraseñas en su aplicación, no modifique este comportamiento.

Otro conveniente incorporado es el requisito de que los nombres de usuario sean únicos. Si lo piensa, si hubiera dos usuarios con el nombre de usuario "djangofan1" y el servidor recibiera una solicitud de inicio de sesión para ese nombre de usuario, no sabría qué usuario estaba tratando de acceder a la aplicación. Desafortunadamente para ellos, el segundo usuario que intente registrarse con “djangofan1” tendrá que elegir un nombre diferente, quizás “djangofan2”. Esta restricción de unicidad se impone a nivel de la base de datos, pero se verifica de nuevo mediante los formularios que proporciona Django.

Finalmente, una nota sobre la eliminación de usuarios. Si bien la eliminación de usuarios es una posibilidad, las aplicaciones más complejas tendrán una cantidad de recursos vinculados a cada cuenta de usuario. Si desea eliminar un usuario de manera efectiva sin eliminar esos objetos adjuntos, establezca el campo is_active del usuario en falso en su lugar. Luego, esos otros recursos permanecen asociados con la cuenta en lugar de eliminarse, y un superusuario puede reactivar la cuenta de usuario en cualquier momento. Tenga en cuenta que esto no libera el nombre de usuario, pero configurar la cuenta como inactiva junto con cambiar el nombre de usuario a un valor único y aleatorio podría lograr el mismo efecto. Finalmente, si las políticas de su sitio o la ley local aplicable requieren que las cuentas de usuario se puedan eliminar por completo, el enfoque is_active no será suficiente.

A menos que tenga experiencia específica y una razón convincente para cambiar la forma en que se manejan las contraseñas en su aplicación, no modifique este comportamiento.

Uso estándar

Cuando desee registrar una nueva cuenta de usuario, la vista para hacerlo probablemente será similar a la siguiente en views.py :

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import UserCreationForm def signup(request): if request.user.is_authenticated: return redirect('/') if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('/') else: return render(request, 'signup.html', {'form': form}) else: form = UserCreationForm() return render(request, 'signup.html', {'form': form})

Vamos a desglosarlo:

  • Si el usuario ya inició sesión, lo redirigiremos fuera de la página de registro.
  • Si el método de solicitud es POST, eso significa que el formulario para crear un usuario ya se completó y es hora de crear un usuario.
    • Primero, construya el objeto de formulario en el backend con los datos proporcionados por el usuario.
    • Si el formulario es válido, cree el usuario e inicie sesión, luego envíelo a la página principal.
    • De lo contrario, vuelva a colocarlos en la página de creación de usuarios con información sobre qué datos no eran válidos (por ejemplo, solicitaron un nombre de usuario que ya estaba en uso).
  • De lo contrario, el usuario está accediendo a la página por primera vez y debe encontrarse con el formulario para crear una nueva cuenta.

Ahora examinando el inicio de sesión de la cuenta:

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import AuthenticationForm def signin(request): if request.user.is_authenticated: return render(request, 'homepage.html') if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('/') else: form = AuthenticationForm(request.POST) return render(request, 'signin.html', {'form': form}) else: form = AuthenticationForm() return render(request, 'signin.html', {'form': form})

Otro desglose:

  • Si el usuario ya inició sesión, lo redirigiremos fuera de la página de inicio de sesión.
  • Si el método de solicitud es POST, eso significa que se completó el formulario para iniciar sesión y es hora de autenticar al usuario en una cuenta.
    • Primero, autentique al usuario con los datos proporcionados por el usuario
    • Si el nombre de usuario y la contraseña corresponden a una cuenta, inicie sesión en el usuario
    • De lo contrario, llévelos de regreso a la página de inicio de sesión con la información del formulario prellenada.
  • En caso contrario, el usuario está accediendo a la página por primera vez y deberá encontrarse con el formulario para iniciar sesión.

Finalmente, es posible que sus usuarios eventualmente deseen cerrar sesión. El código básico para esta solicitud es simple:

 from django.shortcuts import render, redirect from django.contrib.auth import logout def signout(request): logout(request) return redirect('/')

Una vez que el usuario haya iniciado sesión en su cuenta, y hasta que cierre la sesión en ese dispositivo, tendrá una "sesión". Durante este tiempo, las solicitudes posteriores de su navegador podrán acceder a las páginas solo de la cuenta. Un usuario puede tener varias sesiones activas al mismo tiempo. De forma predeterminada, las sesiones no caducan.

Mientras un usuario tenga una sesión activa en su dispositivo, se registrará como True para la verificación request.user.is_authenticated . Otra forma de restringir las páginas solo a los usuarios registrados es el decorador @login_required encima de una función. Hay muchas otras formas de lograr lo mismo, detalladas aquí.

Si este nivel de configuración es más de lo que desea realizar, existe un enfoque aún más innovador para la administración de usuarios. Estas vistas de autenticación estándar proporcionan rutas, vistas y formularios estándar para la administración de usuarios y se pueden modificar asignándolos a URL personalizadas, pasando plantillas personalizadas o incluso subclasificando las vistas para un mayor control.

Ampliación del modelo de usuario

Por lo general, debe expandir el modelo de usuario para proporcionar controles de acceso más detallados o almacenar más datos de usuario por cuenta. Exploraremos varios casos comunes a continuación.

Eliminación de campos del modelo de usuario

Al contrario del encabezado de esta sección, en realidad no recomiendo hacer cambios directamente en el modelo de usuario o en el esquema de la base de datos asociada. El modelo de usuario genérico se establece en su base de datos de forma predeterminada durante la configuración de un nuevo proyecto de Django. Tanto está ligado al modelo de usuario predeterminado que cambiarlo podría tener efectos inesperados en su aplicación (especialmente si está utilizando bibliotecas de terceros), por lo tanto, no se recomienda agregar o eliminar campos y el marco no lo facilita.

De forma predeterminada, los únicos dos campos que se requieren para un usuario son el nombre de usuario y la contraseña. Si no desea utilizar ninguno de los otros campos, simplemente ignore su existencia, ya que se puede crear un usuario sin nombre, apellido o dirección de correo electrónico. Hay una colección de campos predeterminados como last_login y date_joined que también se pueden ignorar si no los desea. Si tuviera una restricción técnica real que requiriera quitar campos opcionales del modelo de usuario, ya la conocería y no necesitaría este artículo.

Una razón común por la que podría querer eliminar un campo en el modelo de usuario es descartar el nombre de usuario a favor del correo electrónico como un identificador único. En ese caso, al crear el usuario a partir de los datos del formulario o autenticar una solicitud, simplemente ingrese la dirección de correo electrónico como nombre de usuario además de su uso en el campo de correo electrónico. El campo de nombre de usuario seguirá imponiendo la restricción de unicidad cuando los nombres de usuario tengan el formato de direcciones de correo electrónico. Las cadenas son cadenas, serán tratadas de la misma manera.

Tanto está ligado al modelo de usuario predeterminado que cambiarlo podría tener efectos inesperados en su aplicación, especialmente si está usando bibliotecas de terceros.

Adición de campos con un perfil

De manera similar, si desea almacenar información adicional sobre sus usuarios, no debe intentar modificar el modelo de usuario predeterminado. Incluso para un solo campo, defina su propio objeto con una relación uno a uno con los usuarios existentes. Este modelo adicional a menudo se denomina Profile . Digamos que desea almacenar un segundo nombre y una fecha de nacimiento (fecha de nacimiento) para cada usuario. El Profile se definiría de la siguiente manera en models.py :

 from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) middle_name = models.CharField(max_length=30, blank=True) dob = models.DateField(null=True, blank=True)

Control de acceso personalizado

Su aplicación puede haber requerido una distinción entre diferentes tipos de usuarios para acceder a información y funciones. Django proporciona un sistema para crear un control de acceso detallado y personalizado: permisos y grupos.

Los permisos son objetos que determinan el acceso a los recursos. Un usuario puede tener uno o más permisos. Por ejemplo, pueden tener acceso de lectura a una tabla de productos y acceso de escritura a una tabla de clientes. La implementación exacta del permiso varía sustancialmente según la aplicación, pero el enfoque de Django hace que sea intuitivo definir permisos para datos y asignar esos permisos a los usuarios.

Las aplicaciones para empresas y otras grandes organizaciones a menudo implementan un control de acceso basado en funciones. Esencialmente, un usuario puede tener varios roles, cada uno de los cuales tiene ciertos permisos. La herramienta de Django para implementar este patrón es Group. Un grupo puede tener cualquier cantidad de permisos, cada uno de los cuales puede asignarse a cualquier cantidad de grupos. Luego, un usuario obtiene permisos no directamente, sino por su pertenencia a grupos, lo que facilita la administración de la aplicación.

Descripción general: integración de un proveedor de pago

El proceso preciso de integración de un procesador de pagos varía sustancialmente según la aplicación y el proveedor. Sin embargo, cubriré el proceso en términos generales.

Una de las principales ventajas de la subcontratación de pagos es que el proveedor es responsable de almacenar y validar datos altamente regulados, como la información de la tarjeta de crédito. Luego, el servicio comparte un token de usuario único con su aplicación junto con datos sobre su historial de pago. Al igual que agregar el perfil, puede crear un modelo asociado con el User principal y almacenar los datos en ese modelo. Al igual que con las contraseñas, es importante seguir la integración dada con el proveedor para evitar almacenar información confidencial de manera incorrecta.

Descripción general: inicio de sesión social

El otro campo amplio y complejo al que quiero referirme brevemente es el inicio de sesión social. Grandes plataformas como Facebook y Google, así como sitios más pequeños como GitHub, proporcionan API para usar sus servicios para autenticar a los usuarios. Similar a un proveedor de pagos, esto crea un registro en su base de datos que vincula una cuenta a una cuenta en su base de datos.

Es posible que desee incluir autenticación social en su sitio para que sea más fácil para los usuarios registrarse sin crear un nuevo conjunto de credenciales de inicio de sesión. Si su aplicación se dirige únicamente a clientes que ya usan un sitio específico que ofrece una opción de autenticación social, podría ayudarlo a atraer usuarios de ese mercado al reducir la barrera de entrada. Además, si su aplicación pretende acceder a los datos del usuario desde un servicio de terceros, vincular las cuentas durante la autenticación simplifica el proceso de concesión de permisos.

Sin embargo, existen desventajas en el uso de la autenticación social. Los cambios en la API o las interrupciones del proveedor externo podrían interrumpir el tiempo de actividad o las actividades de desarrollo de su aplicación. En general, las dependencias externas agregan complejidad a la aplicación. Finalmente, vale la pena considerar las políticas de recopilación y uso de datos de terceros con los que se está integrando y asegurarse de que se alineen con sus expectativas y las de sus usuarios.

Si decide que la autenticación social es adecuada para su aplicación, afortunadamente, hay una biblioteca para eso. Python Social Auth for Django es un paquete para habilitar las capacidades del ecosistema de autenticación social de Python en proyectos de Django.

Terminando

Tan universal como es la cuenta de usuario, su uso generalizado puede llevar a resolver los mismos problemas innecesariamente. Esperamos que este artículo le haya mostrado la gama de potentes funciones disponibles en Django y le haya dado una idea de las responsabilidades básicas de una aplicación al crear cuentas de usuario.

Django Highlights es una serie que presenta conceptos importantes del desarrollo web en Django. Cada artículo está escrito como una guía independiente de una faceta del desarrollo de Django con la intención de ayudar a los desarrolladores y diseñadores front-end a alcanzar una comprensión más profunda de "la otra mitad" de la base de código. Estos artículos se construyen principalmente para ayudarlo a comprender la teoría y la convención, pero contienen algunos ejemplos de código, que están escritos en Django 3.0. Varios conceptos que mencionamos en este artículo, incluidas plantillas, usuarios administradores, modelos y formularios, se explorarán individualmente en detalle en futuros artículos de esta serie.

Otras partes de la serie:

  • Aspectos destacados de Django: creación de plantillas de líneas de guardado (parte 2)
  • Aspectos destacados de Django: modelos, administración y aprovechamiento de la base de datos relacional (parte 3)
  • Aspectos destacados de Django: disputa de activos estáticos y archivos multimedia (Parte 4)