tutorial - gestion de usuarios django
Inicio de sesión manual en un usuario sin contraseña (5)
Espero que pueda ayudarme a encontrar la mejor forma de implementar un inicio de sesión manual (iniciado por el servidor) sin usar la contraseña. Déjame explicar el flujo de trabajo:
- Registros de usuario
- ¡Gracias! Se ha enviado un correo electrónico con un enlace de activación blablabla
- (La cuenta ahora existe pero está marcada como no habilitada)
- El usuario abre el correo electrónico, hace clic en el enlace
- (Cuenta habilitada)
- ¡Gracias! Ahora puedes usar el sitio
Lo que estoy tratando de hacer es iniciar sesión en el usuario después de que haya hecho clic en el enlace del correo electrónico para que pueda comenzar a utilizar el sitio web de inmediato.
No puedo usar su contraseña porque está encriptada en la base de datos, ¿es la única opción que escribe un back-end de autenticación personalizado?
A partir de Django 1.10, el proceso se ha simplificado.
En todas las versiones de Django, para que un usuario inicie sesión, debe ser autenticado por uno de los servidores de la aplicación (controlado por la configuración de AUTHENTICATION_BACKENDS
).
Si simplemente desea forzar un inicio de sesión, puede simplemente afirmar que el usuario fue autenticado por el primer back-end de esa lista:
from django.conf import settings
from django.contrib.auth import login
# Django 1.10+
login(request, user, backend=settings.settings.AUTHENTICATION_BACKENDS[0])
# Django <1.10 - fake the authenticate() call
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(request, user)
La respuesta de Daniel es muy buena.
Otra forma de hacerlo es crear un HashModelBackend siguiendo los backends de Autorización personalizada https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend como este:
class HashModelBackend(object):
def authenticate(self, hash=None):
user = get_user_from_hash(hash)
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Y luego instálalo en tu configuración:
AUTHENTICATION_BACKENDS = (
''myproject.backends.HashModelBackend'',
''django.contrib.auth.backends.ModelBackend'',
)
Entonces tu punto de vista sería algo como esto:
def activate_account(request, hash):
user = authenticate(hash=hash)
if user:
# check if user is_active, and any other checks
login(request, user)
else:
return user_not_found_bad_hash_message
Puede usar el paquete ska
, que tiene un inicio de sesión sin contraseña para implementar Django. ska
funciona con tokens de autenticación y su seguridad se basa en SHARED_KEY, que debe ser igual para todas las partes involucradas (servidores).
En el lado del cliente (parte que solicita un inicio de sesión sin contraseña), usted genera una URL y la firma usando ska
. Ejemplo:
from ska import sign_url
from ska.contrib.django.ska.settings import SECRET_KEY
server_ska_login_url = ''https://server-url.com/ska/login/''
signed_url = sign_url(
auth_user = ''test_ska_user_0'',
secret_key = SECRET_KEY,
url = server_ska_login_url
extra = {
''email'': ''[email protected]'',
''first_name'': ''John'',
''last_name'': ''Doe'',
}
)
La vida útil predeterminada del token es de 600 segundos. Puede personalizar eso probando un argumento de por lifetime
.
En el lado del servidor (sitio al que los usuarios inician sesión), teniendo en cuenta que ha instalado ska
correctamente, el usuario ha iniciado sesión visitando la URL si existieron (coincidencia de nombre de usuario), o bien creado. Hay 3 devoluciones de llamada que puede personalizar en la configuración de Django de su proyecto.
USER_GET_CALLBACK (cadena): activada si el usuario fue recuperado correctamente de la base de datos (usuario existente). USER_CREATE_CALLBACK (cadena): disparada justo después de que se haya creado el usuario (el usuario no existía). USER_INFO_CALLBACK (cadena): activada tras una autenticación exitosa.
Consulte la documentación ( http://pythonhosted.org/ska/ ) para obtener más información.
Respuesta a la respuesta de Dan .
Una forma de escribir tu backend:
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class HashModelBackend(ModelBackend):
def authenticate(self, username=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
return user
except UserModel.DoesNotExist:
return None
La respuesta se basa en el código fuente django.contrib.auth.backends.ModelBackend . Es real para django 1.9
Y prefiero situar el backend personalizado debajo del predeterminado de django:
AUTHENTICATION_BACKENDS = [
''django.contrib.auth.backends.ModelBackend'',
''yours.HashModelBackend'',
]
porque la activación de la cuenta es menos posible que el inicio de sesión. De acuerdo con https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#specifying-authentication-backends :
El orden de AUTHENTICATION_BACKENDS es importante, por lo que si el mismo nombre de usuario y la contraseña son válidos en varios servidores, Django detendrá el procesamiento en la primera coincidencia positiva.
Tenga cuidado con este código autenticará a sus usuarios incluso con contraseñas incorrectas.
No necesita una contraseña para registrar a un usuario. La función auth.login
simplemente toma un objeto User
, que presumiblemente ya está obteniendo de la base de datos cuando habilita la cuenta. Entonces puede pasar eso directamente para login
.
Por supuesto, tendrá que tener mucho cuidado de que no haya manera de que un usuario pueda falsificar un enlace a una cuenta existente ya habilitada, lo que luego automáticamente los iniciará como ese usuario.
from django.contrib.auth import login
def activate_account(request, hash):
account = get_account_from_hash(hash)
if not account.is_active:
account.activate()
account.save()
user = account.user
login(request, user)
... etc.
Editado :
Hmm, no noté ese requisito de usar authenticate
debido a la propiedad adicional que agrega. Al mirar el código, todo lo que hace es un atributo de backend
equivalente a la ruta del módulo del backend de autenticación. Entonces podría simplemente simularlo: antes de la llamada de inicio de sesión anterior, haga esto:
user.backend = ''django.contrib.auth.backends.ModelBackend''