usuarios tutorial manage gestion createsuperuser django login django-authentication email-confirmation

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''