| name | auth-system-builder |
| description | Genera sistema completo de autenticación para Django con registro, login, verificación de email, recuperación de contraseña, social auth y protección de vistas. Usa django-allauth y best practices de seguridad. |
Auth System Builder - Django
Propósito
Este skill genera sistemas de autenticación completos para Django que puedes implementar en 15 minutos. Incluye todo el código necesario: registro, login, verificación de email, recuperación de contraseña, social authentication (Google, GitHub) y protección de vistas.
Stack Tecnológico
Framework: Django 4.x / 5.x
Paquetes principales:
django-allauth(auth social + email verification)django-crispy-forms(formularios bonitos)crispy-bootstrap5(estilos Bootstrap 5)
Base de datos: PostgreSQL / SQLite (desarrollo)
Cuándo Usar Este Skill
✅ Agregar autenticación completa a proyecto Django nuevo
✅ Registro con verificación de email obligatoria
✅ Login con email o username
✅ Recuperación de contraseña por email
✅ Social login (Google, GitHub, Facebook)
✅ Protección de vistas con decoradores
✅ User profile extendido
Instalación Rápida (15 minutos)
1. Instalar Dependencias
pip install django-allauth django-crispy-forms crispy-bootstrap5
pip freeze > requirements.txt
2. Configurar settings.py
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites', # REQUERIDO por allauth
# Apps de terceros
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google', # OAuth Google
'allauth.socialaccount.providers.github', # OAuth GitHub
'crispy_forms',
'crispy_bootstrap5',
# Tus apps
# 'miapp',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'allauth.account.middleware.AccountMiddleware', # AGREGAR ESTO
]
# Site ID requerido por django-allauth
SITE_ID = 1
# Authentication backends
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
]
# Configuración de django-allauth
ACCOUNT_AUTHENTICATION_METHOD = 'email' # Login con email
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory' # Obligatorio verificar email
ACCOUNT_USERNAME_REQUIRED = False # No requerir username
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = True # Confirmar email en registro
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 300 # 5 minutos
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
ACCOUNT_SESSION_REMEMBER = True
# URLs de redirección
LOGIN_REDIRECT_URL = '/dashboard/'
ACCOUNT_LOGOUT_REDIRECT_URL = '/accounts/login/'
LOGIN_URL = '/accounts/login/'
# Email backend (desarrollo)
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Email backend (producción - ejemplo con Gmail)
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_PORT = 587
# EMAIL_USE_TLS = True
# EMAIL_HOST_USER = 'tu-email@gmail.com'
# EMAIL_HOST_PASSWORD = 'tu-app-password'
# DEFAULT_FROM_EMAIL = 'tu-email@gmail.com'
# Crispy Forms
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
# Seguridad (producción)
# SESSION_COOKIE_SECURE = True
# CSRF_COOKIE_SECURE = True
# SECURE_SSL_REDIRECT = True
3. Configurar URLs principales
# proyecto/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')), # Todas las URLs de auth
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('dashboard/', TemplateView.as_view(template_name='dashboard.html'), name='dashboard'),
]
4. Migrar Base de Datos
python manage.py migrate
python manage.py createsuperuser
5. Crear Site en Admin
python manage.py shell
from django.contrib.sites.models import Site
site = Site.objects.get(id=1)
site.domain = 'localhost:8000' # o tu dominio
site.name = 'Mi Sitio'
site.save()
Templates Base
Base Template
Archivo: templates/base.html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Mi Sitio{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'home' %}">Mi Sitio</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'dashboard' %}">Dashboard</a>
</li>
<li class="nav-item">
<span class="nav-link">Hola, {{ user.email }}</span>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'account_logout' %}">Cerrar Sesión</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'account_login' %}">Iniciar Sesión</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'account_signup' %}">Registrarse</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<main class="container my-5">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Home Page
Archivo: templates/home.html
{% extends 'base.html' %}
{% block content %}
<div class="text-center">
<h1 class="display-4">Bienvenido</h1>
<p class="lead">Sistema de autenticación completo con Django</p>
{% if not user.is_authenticated %}
<div class="mt-4">
<a href="{% url 'account_signup' %}" class="btn btn-primary btn-lg">Crear Cuenta</a>
<a href="{% url 'account_login' %}" class="btn btn-outline-primary btn-lg">Iniciar Sesión</a>
</div>
{% else %}
<div class="mt-4">
<a href="{% url 'dashboard' %}" class="btn btn-primary btn-lg">Ir al Dashboard</a>
</div>
{% endif %}
</div>
{% endblock %}
Dashboard (Protegido)
Archivo: templates/dashboard.html
{% extends 'base.html' %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-8 mx-auto">
<h1 class="mb-4">Dashboard</h1>
<div class="card">
<div class="card-header">
<h5 class="mb-0">Información del Usuario</h5>
</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-3">Email:</dt>
<dd class="col-sm-9">{{ user.email }}</dd>
<dt class="col-sm-3">Usuario:</dt>
<dd class="col-sm-9">{{ user.username|default:"No configurado" }}</dd>
<dt class="col-sm-3">Email verificado:</dt>
<dd class="col-sm-9">
{% if user.emailaddress_set.first.verified %}
<span class="badge bg-success">Sí</span>
{% else %}
<span class="badge bg-warning">No</span>
{% endif %}
</dd>
<dt class="col-sm-3">Fecha de registro:</dt>
<dd class="col-sm-9">{{ user.date_joined|date:"d/m/Y H:i" }}</dd>
</dl>
<div class="mt-3">
<a href="{% url 'account_email' %}" class="btn btn-primary">Gestionar Emails</a>
<a href="{% url 'account_change_password' %}" class="btn btn-secondary">Cambiar Contraseña</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Personalizar Templates de django-allauth
Crea carpeta templates/account/ y sobrescribe templates:
Login Personalizado
Archivo: templates/account/login.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Iniciar Sesión{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="card-title text-center mb-4">Iniciar Sesión</h2>
<form method="post" action="{% url 'account_login' %}">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary w-100 mb-3">Iniciar Sesión</button>
</form>
<div class="text-center mb-3">
<a href="{% url 'account_reset_password' %}" class="text-muted small">
¿Olvidaste tu contraseña?
</a>
</div>
<hr>
<p class="text-center mb-3 text-muted">O inicia sesión con:</p>
<div class="d-grid gap-2">
<a href="{% url 'google_login' %}" class="btn btn-outline-danger">
<i class="fab fa-google"></i> Continuar con Google
</a>
<a href="{% url 'github_login' %}" class="btn btn-outline-dark">
<i class="fab fa-github"></i> Continuar con GitHub
</a>
</div>
<p class="text-center mt-4 mb-0">
¿No tienes cuenta?
<a href="{% url 'account_signup' %}">Regístrate aquí</a>
</p>
</div>
</div>
</div>
</div>
{% endblock %}
Registro Personalizado
Archivo: templates/account/signup.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Registro{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card shadow">
<div class="card-body p-5">
<h2 class="card-title text-center mb-4">Crear Cuenta</h2>
<form method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary w-100 mb-3">Crear Cuenta</button>
</form>
<hr>
<p class="text-center mb-3 text-muted">O regístrate con:</p>
<div class="d-grid gap-2">
<a href="{% url 'google_login' %}" class="btn btn-outline-danger">
<i class="fab fa-google"></i> Continuar con Google
</a>
<a href="{% url 'github_login' %}" class="btn btn-outline-dark">
<i class="fab fa-github"></i> Continuar con GitHub
</a>
</div>
<p class="text-center mt-4 mb-0">
¿Ya tienes cuenta?
<a href="{% url 'account_login' %}">Inicia sesión aquí</a>
</p>
</div>
</div>
</div>
</div>
{% endblock %}
Protección de Vistas
Con Decorador (Function-Based Views)
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
@login_required
def dashboard_view(request):
return render(request, 'dashboard.html')
Con Mixin (Class-Based Views)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class DashboardView(LoginRequiredMixin, TemplateView):
template_name = 'dashboard.html'
login_url = '/accounts/login/'
Modelo de Usuario Extendido
Si necesitas campos adicionales en el usuario:
# miapp/models.py
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
phone = models.CharField(max_length=20, blank=True)
bio = models.TextField(max_length=500, blank=True)
birth_date = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
def __str__(self):
return f'Perfil de {self.user.email}'
# Crear Profile automáticamente al crear User
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
python manage.py makemigrations
python manage.py migrate
Configurar OAuth (Google)
1. Crear proyecto en Google Cloud Console
- Ve a https://console.cloud.google.com
- Crea nuevo proyecto
- Habilita "Google+ API"
- Ve a "Credentials" > "Create Credentials" > "OAuth 2.0 Client ID"
- Tipo: Web application
- Authorized redirect URIs:
http://localhost:8000/accounts/google/login/callback/https://tudominio.com/accounts/google/login/callback/
2. Configurar en Django Admin
- Inicia sesión en
/admin/ - Ve a "Social applications" > "Add social application"
- Provider: Google
- Name: Google OAuth
- Client ID: [tu client id]
- Secret key: [tu client secret]
- Sites: Selecciona tu site
- Save
Email Templates Personalizados
Archivo: templates/account/email/email_confirmation_subject.txt
Confirma tu email en {{ site_name }}
Archivo: templates/account/email/email_confirmation_message.txt
Hola {{ user.email }},
Gracias por registrarte en {{ site_name }}.
Para completar tu registro, por favor confirma tu dirección de email haciendo click en el siguiente enlace:
{{ activate_url }}
Este enlace expira en {{ expiration_days }} días.
Saludos,
El equipo de {{ site_name }}
Configuración de Email en Producción
Con Gmail (menos seguro)
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'tu-email@gmail.com'
EMAIL_HOST_PASSWORD = 'tu-app-password' # Generar en Google Account
DEFAULT_FROM_EMAIL = 'tu-email@gmail.com'
Con SendGrid (recomendado)
pip install sendgrid
# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'tu-api-key-de-sendgrid'
DEFAULT_FROM_EMAIL = 'noreply@tudominio.com'
Checklist de Implementación
- Instalar django-allauth y crispy-forms
- Configurar INSTALLED_APPS
- Configurar AUTHENTICATION_BACKENDS
- Configurar account settings en settings.py
- Configurar URLs principales
- Ejecutar migraciones
- Crear Site en admin
- Crear templates base
- Personalizar templates de login/signup
- Configurar email backend
- Probar registro + verificación de email
- Probar login/logout
- Probar recuperación de contraseña
- Configurar OAuth providers (opcional)
- Implementar Profile model (opcional)
Comandos Útiles
# Verificar configuración de email
python manage.py shell
from django.core.mail import send_mail
send_mail('Test', 'Mensaje', 'from@example.com', ['to@example.com'])
# Limpiar sesiones expiradas
python manage.py clearsessions
# Crear usuario de prueba
python manage.py shell
from django.contrib.auth.models import User
User.objects.create_user('test@example.com', 'test@example.com', 'password123')
Troubleshooting
Error: "Site matching query does not exist"
python manage.py shell
from django.contrib.sites.models import Site
Site.objects.create(domain='localhost:8000', name='Dev Site')
Email no llega en desarrollo:
- Verifica
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - El email se imprime en la consola, no se envía realmente
OAuth redirect mismatch:
- Verifica que las URLs en Google Console coincidan exactamente
- Incluye http:// o https://
- No olvides la barra final /
Formato de Output
Cuando uses este skill, especifica:
- Si necesitas OAuth (Google, GitHub, etc.)
- Si necesitas Profile extendido
- Si necesitas email templates personalizados
Ejemplo:
"Implementa autenticación completa con django-allauth.
Necesito registro con verificación de email, OAuth con Google,
y un modelo Profile con teléfono y avatar."
El skill generará todo el código necesario listo para implementar.