102 votes

Django - Connexion avec l'email

Je veux que django authentifie les utilisateurs par e-mail, et non par nom d'utilisateur. Une façon de faire est de fournir la valeur de l'email comme valeur du nom d'utilisateur, mais je ne veux pas cela. La raison en est que j'ai une url /profile/<username>/ donc je ne peux pas avoir d'url /profile/abcd@gmail.com/ .

Une autre raison est que tous les emails sont uniques, mais il arrive parfois que le nom d'utilisateur soit déjà pris. C'est pourquoi je crée automatiquement le nom d'utilisateur en tant que fullName_ID .

Comment puis-je changer le fait que Django s'authentifie avec l'email ?

Voici comment je crée un utilisateur.

username = `abcd28`
user_email = `abcd@gmail.com`
user = User.objects.create_user(username, user_email, user_pass)

C'est ainsi que je me connecte.

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)

Existe-t-il un autre moyen de se connecter, à part obtenir le nom d'utilisateur en premier ?

5voto

Gabriel Garcia Points 288

Authentification par courriel et nom d'utilisateur pour Django 2.X

Sachant qu'il s'agit d'une question fréquente, voici une mise en œuvre personnalisée qui imite l'approche de l'UE. Code source de Django mais qui authentifie l'utilisateur à l'aide de son nom d'utilisateur ou de son adresse électronique, sans tenir compte des cas particuliers, en conservant l'adresse de l'utilisateur. attaque chronométrique protection y non authentification des utilisateurs inactifs .

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

N'oubliez pas d'ajouter dans votre fichier settings.py le bon numéro d'enregistrement. Backend d'authentification .

1 votes

Est-ce que je comprends bien que le UserModel().set_password(password) est là pour empêcher les attaquants de déterminer si un utilisateur existe ou n'existe pas en effectuant à peu près la même quantité de travail cryptographique (je suppose qu'il s'agit de l'attaque de synchronisation dont vous parliez) ?

2voto

Hùng Ng Vi Points 388

Vous devez personnaliser la classe ModelBackend. Mon code 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

Et dans paramètres.py fichier, ajouter :

AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend']

0 votes

Mettez à jour votre code pour inclure request dans authenticate méthode pour django 2.1.1

2voto

Chetan Points 21

Authentification par courriel et nom d'utilisateur pour 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

Dans settings.py, ajoutez la ligne suivante,

AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']

1voto

Animesh Timsina Points 77
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

Et ensuite dans settings.py :

AUTHENTICATION_BACKENDS = (
  'articles.backends.EmailAuthenticate',
)

où articles est mon django-app, backends.py est le fichier python dans mon application et EmailAuthenticate est la classe du backend d'authentification dans mon backends.py fichier

1voto

Wariored Points 414

J'ai créé une aide pour cela : fonction 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)

0 votes

Une solution simple et directe ! Elle fonctionnera, sauf si vous avez plusieurs utilisateurs sous le même email. C'est une implémentation plutôt sympa

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X