Quiero que django autentique a los usuarios por correo electrónico, no a través de nombres de usuario. Una forma puede ser proporcionar valor de correo electrónico como valor de nombre de usuario, pero no quiero eso. La razón es que tengo una URL /profile/<username>/
, por lo tanto, no puedo tener una URL /profile/[email protected]/
.
Otra razón es que todos los correos electrónicos son únicos, pero a veces sucede que el nombre de usuario ya está siendo tomado. Por lo tanto, estoy creando automáticamente el nombre de usuario como fullName_ID
.
¿Cómo puedo dejar que Django se autentique con el correo electrónico?
Así es como creo un usuario.
username = `abcd28`
user_email = `[email protected]`
user = User.objects.create_user(username, user_email, user_pass)
Así es como me conecto.
email = request.POST['email']
password = request.POST['password']
username = User.objects.get(email=email.lower()).username
user = authenticate(username=username, password=password)
login(request, user)
¿Hay alguna otra forma de iniciar sesión además de obtener el nombre de usuario primero?
if user.check_password(password):
, probablemente desee incluir lo que Django hace de forma predeterminada a través deModelBackend
:if user.check_password(password) and self.user_can_authenticate(user):
para verificar que el usuario tieneis_active=True
.Si está iniciando un nuevo proyecto, django le recomendó que configure un modelo de usuario personalizado. (ver https://docs.djangoproject.com/en/dev/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project )
y si lo hizo, agregue tres líneas a su modelo de usuario:
class MyUser(AbstractUser): USERNAME_FIELD = 'email' email = models.EmailField(_('email address'), unique=True) # changes email to unique and blank to false REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS
Luego
authenticate(email=email, password=password)
funciona, mientrasauthenticate(username=username, password=password)
deja de funcionar.fuente
class MyUserManager(BaseUserManager): def create_superuser(self, email, password, **kwargs): user = self.model(email=email, is_staff=True, is_superuser=True, **kwargs) user.set_password(password) user.save() return user
Autenticación de correo electrónico para Django 3.x
Para usar correo electrónico / nombre de usuario y contraseña para la autenticación en lugar del nombre de usuario y contraseña predeterminados, necesitamos anular dos métodos de la clase ModelBackend: authenticate () y get_user ():
El método get_user toma un user_id, que podría ser un nombre de usuario, un ID de base de datos o lo que sea, pero debe ser único para su objeto de usuario , y devuelve un objeto de usuario o Ninguno. Si no ha mantenido el correo electrónico como clave única, tendrá que encargarse de los resultados múltiples devueltos para query_set. En el siguiente código, esto se solucionó devolviendo el primer usuario de la lista devuelta.
from django.contrib.auth.backends import ModelBackend, UserModel from django.db.models import Q class EmailBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: #to allow authentication through phone number or any other field, modify the below statement user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: UserModel().set_password(password) except MultipleObjectsReturned: return User.objects.filter(email=username).order_by('id').first() else: if user.check_password(password) and self.user_can_authenticate(user): return user def get_user(self, user_id): try: user = UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None
De forma predeterminada, AUTHENTICATION_BACKENDS está configurado en:
['django.contrib.auth.backends.ModelBackend']
En el archivo settings.py, agregue lo siguiente en la parte inferior para anular el valor predeterminado:
AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)
fuente
Tenía un requisito similar en el que el nombre de usuario / correo electrónico debería funcionar para el campo de nombre de usuario. En caso de que alguien esté buscando la forma de autenticación de backend para hacer esto, consulte el siguiente código de trabajo. Puede cambiar el conjunto de consultas si solo desea el correo electrónico.
from django.contrib.auth import get_user_model # gets the user_model django default or your own custom from django.contrib.auth.backends import ModelBackend from django.db.models import Q # Class to permit the athentication using email or username class CustomBackend(ModelBackend): # requires to define two functions authenticate and get_user def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() try: # below line gives query set,you can change the queryset as per your requirement user = UserModel.objects.filter( Q(username__iexact=username) | Q(email__iexact=username) ).distinct() except UserModel.DoesNotExist: return None if user.exists(): ''' get the user object from the underlying query set, there will only be one object since username and email should be unique fields in your models.''' user_obj = user.first() if user_obj.check_password(password): return user_obj return None else: return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None
También agregue AUTHENTICATION_BACKENDS = ('path.to.CustomBackend',) en settings.py
fuente
Django 2.x
Como mencionó Ganesh anteriormente para django 2.x, el método de autenticación ahora requiere un parámetro de solicitud.
# backends.py from django.contrib.auth import backends, get_user_model from django.db.models import Q UserModel = get_user_model() class ModelBackend(backends.ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: # user = UserModel._default_manager.get_by_natural_key(username) # You can customise what the given username is checked against, here I compare to both username and email fields of the User model user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a nonexistent user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user return super().authenticate(request, username, password, **kwargs)
agregue su backend a la configuración de su proyecto
# settings.py AUTHENTICATION_BACKENDS = ['path.to.ModelBackend']
Su modelo de usuario personalizado deberá hacer que los correos electrónicos sean únicos para los usuarios activos y validados. Puede hacerlo simplemente con algo como esto:
from django.contrib.auth.models import AbstractUser class User(AbstractUser): objects = UserManager() email = models.EmailField(_('email address'), unique=True) class Meta: verbose_name = _('user') verbose_name_plural = _('users') db_table = 'auth_user' swappable = 'AUTH_USER_MODEL'
Pero para evitar que alguien bloquee a otra persona para que no use su correo electrónico, debe agregar la validación del correo electrónico y hacer que su proceso de registro e inicio de sesión tenga en cuenta que los correos electrónicos pueden no ser únicos (y probablemente evitar que los nuevos usuarios usen una dirección de correo electrónico existente y validada).
fuente
Autenticación de correo electrónico y nombre de usuario para Django 2.X
Teniendo en cuenta que esta es una pregunta común, aquí hay una implementación personalizada que imita la código fuente de Django pero que autentica al usuario con nombre de usuario o correo electrónico, sin distinción de mayúsculas y minúsculas, manteniendo la protección contra ataques de tiempo y no autenticando a los usuarios inactivos .
from django.contrib.auth.backends import ModelBackend, UserModel from django.db.models import Q class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user def get_user(self, user_id): try: user = UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None return user if self.user_can_authenticate(user) else None
Recuerde siempre agregarlo a su settings.py el correcto backend de autenticación .
fuente
UserModel().set_password(password)
existe para evitar que los atacantes determinen si un usuario existe o no al realizar aproximadamente la misma cantidad de trabajo criptográfico independientemente (supongo que este es el ataque de tiempo al que se refería)?Debe personalizar la clase ModelBackend. Mi código simple:
from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model class YourBackend(ModelBackend): def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: if '@' in username: UserModel.USERNAME_FIELD = 'email' else: UserModel.USERNAME_FIELD = 'username' user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user
Y en el archivo settings.py , agregue:
AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend']
fuente
request
parámetro en elauthenticate
método para django 2.1.1Autenticación con correo electrónico y nombre de usuario para Django 2.x
from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend from django.db.models import Q class EmailorUsernameModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username)) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None
En settings.py, agregue la siguiente línea,
AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']
fuente
from django.contrib.auth.models import User from django.db import Q class EmailAuthenticate(object): def authenticate(self, username=None, password=None, **kwargs): try: user = User.objects.get(Q(email=username) | Q(username=username)) except User.DoesNotExist: return None except MultipleObjectsReturned: return User.objects.filter(email=username).order_by('id').first() if user.check_password(password): return user return None def get_user(self,user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None
Y luego en
settings.py
:donde los artículos es mi django-app,
backends.py
es el archivo de Python dentro de mi aplicación yEmailAuthenticate
es la clase de backend de autenticación dentro de mibackends.py
archivofuente
Bastante simple. No hay necesidad de clases adicionales.
Cuando crea y actualiza un usuario con un correo electrónico, simplemente configure el campo de nombre de usuario con el correo electrónico.
De esa manera, cuando se autentique, el campo de nombre de usuario tendrá el mismo valor que el correo electrónico.
El código:
# Create User.objects.create_user(username=post_data['email'] etc...) # Update user.username = post_data['email'] user.save() # When you authenticate user = authenticate(username=post_data['email'], password=password)
fuente
Para Django 2
username = get_object_or_404(User, email=data["email"]).username user = authenticate( request, username = username, password = data["password"] ) login(request, user)
fuente
Autenticación con correo electrónico para Django 2.x
def admin_login(request): if request.method == "POST": email = request.POST.get('email', None) password = request.POST.get('password', None) try: get_user_name = CustomUser.objects.get(email=email) user_logged_in =authenticate(username=get_user_name,password=password) if user_logged_in is not None: login(request, user_logged_in) messages.success(request, f"WelcomeBack{user_logged_in.username}") return HttpResponseRedirect(reverse('backend')) else: messages.error(request, 'Invalid Credentials') return HttpResponseRedirect(reverse('admin_login')) except: messages.warning(request, 'Wrong Email') return HttpResponseRedirect(reverse('admin_login')) else: if request.user.is_authenticated: return HttpResponseRedirect(reverse('backend')) return render(request, 'login_panel/login.html')
fuente
Si creó una base de datos personalizada, desde allí, si desea validar su identificación de correo electrónico y contraseña.
models.objects.value_list('db_columnname').filter(db_emailname=textbox email)
2.asignar en la lista recuperada
object_query_list
3.Convertir lista en cadena
Ej .:
Tome el HTML
Email_id
y losPassword
valores enViews.py
u_email = request.POST.get('uemail')
u_pass = request.POST.get('upass')
Obtener el ID de correo electrónico y la contraseña de la base de datos
Email = B_Reg.objects.values_list('B_Email',flat=True).filter(B_Email=u_email)
Password = B_Reg.objects.values_list('Password',flat=True).filter(B_Email=u_email)
Tome los valores de ID de correo electrónico y contraseña en la lista del
Query
conjunto de valoresEmail_Value = Email[0]
Password_Value=Password[0]
Convertir lista en cadena
string_email = ''.join(map(str, Email_Value))
string_password = ''.join(map(str, Password_Value))
Finalmente su condición de inicio de sesión
if (string_email==u_email and string_password ==u_pass)
fuente
He creado un ayudante para eso: función
authenticate_user(email, password)
.from django.contrib.auth.models import User def authenticate_user(email, password): try: user = User.objects.get(email=email) except User.DoesNotExist: return None else: if user.check_password(password): return user return None class LoginView(View): template_name = 'myapp/login.html' def get(self, request): return render(request, self.template_name) def post(self, request): email = request.POST['email'] password = request.POST['password'] user = authenticate_user(email, password) context = {} if user is not None: if user.is_active: login(request, user) return redirect(self.request.GET.get('next', '/')) else: context['error_message'] = "user is not active" else: context['error_message'] = "email or password not correct" return render(request, self.template_name, context)
fuente
Parece que el método para hacer esto se ha actualizado con Django 3.0.
Un método de trabajo para mí ha sido:
authentication.py # <: coloqué esto en una aplicación (no funcionó en la carpeta del proyecto junto con settings.py
from django.contrib.auth import get_user_model from django.contrib.auth.backends import BaseBackend from django.contrib.auth.hashers import check_password from django.contrib.auth.models import User class EmailBackend(BaseBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email=username) except UserModel.DoesNotExist: return None else: if user.check_password(password): return user return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None
Luego agregó esto al archivo settings.py
fuente