2016-05-19 14 views
28

Ich möchte Django Benutzer über E-Mail authentifizieren, nicht über Benutzernamen. Eine Möglichkeit kann darin bestehen, einen E-Mail-Wert als Benutzernamen anzugeben, aber das möchte ich nicht. Grund ist, ich habe eine URL /profile/<username>/, daher kann ich keine URL /profile/[email protected]/ haben.Django - Login mit E-Mail

Ein weiterer Grund ist, dass alle E-Mails eindeutig sind, aber manchmal wird der Benutzername bereits vergeben. Daher erstelle ich den Benutzernamen automatisch als fullName_ID.

Wie kann ich nur ändern lassen Django mit E-Mail authentifizieren?

So erstelle ich einen Benutzer.

username = `abcd28` 
user_email = `[email protected]` 
user = User.objects.create_user(username, user_email, user_pass) 

So logge ich mich ein.

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) 

Gibt es einen anderen Login als den Benutzernamen zuerst?

Antwort

38

Sie sollten ein benutzerdefiniertes Authentifizierungs-Backend schreiben. So etwas wie dies funktioniert:

from django.contrib.auth import get_user_model 
from django.contrib.auth.backends import ModelBackend 

class EmailBackend(ModelBackend): 
    def authenticate(self, 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 

Dann eingestellt, dass Backend als Authentifizierungs-Backend in Ihren Einstellungen:

AUTHENTICATION_BACKENDS = ['path.to.auth.module.EmailBackend'] 

aktualisiert. Erben von ModelBackend, da es bereits Methoden wie get_user() implementiert.

+0

Nice one. Thxs. Frage war auch sehr nützlich @ PythonEnthusiast. – AlessMascherpa

+0

Fehler im Code: UserMode.DoesNotExist – cyberbudy

+5

Verwenden von Django 1.9.8 Ich habe einen Fehler: 'EmailBackend' Objekt hat kein Attribut 'get_user'. Gelöst durch Hinzufügen der 'get_user'-Methode gemäß diesem http: // stackoverflow.com/a/13954358/2647009 – baltasvejas

2

Ich hatte eine ähnliche Anforderung, wo entweder Benutzername/E-Mail für das Feld Benutzername funktionieren sollte. Wenn jemand nach dem Authentifizierungs-Back-End-Weg sucht, überprüfen Sie den folgenden Arbeitscode.Sie können das Suchfeld ändern, wenn Sie möchten nur die E-Mail.

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 

Auch AUTHENTICATION_BACKENDS = ('path.to.CustomBackend') in settings.py

+0

Das funktioniert gut für mich! – Gui

+0

@GuilhermeJunqueira: cool! – anuragb26

2

Sie sollten ModelBackend Klasse anpassen hinzuzufügen. Mein einfacher Code:

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 

Und in settings.py Datei hinzufügen:

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

Wenn Sie ein neues Projekt fangen, django empfohlen, dass Sie hoch ein benutzerdefinierten einrichten Benutzermodell. (Siehe https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)

und wenn Sie es getan haben, fügen Sie drei Zeilen zu Ihrem Benutzermodell:

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 

Dann Werke, während authenticate(username=username, password=password) nicht mehr funktioniert.

+0

Wenn createsuperuser ausgeführt wird, wird selbst ein Fehler ausgegeben: TypeError: create_superuser() fehlt 1 erforderliches Positionsargument: 'username'. Sie müssen benutzerdefinierte Benutzermanager verwenden: 'Klasse MyUserManager (BaseUserManager): def create_superuser (self, E-Mail, Passwort, ** kwargs): user = self.model (email = E-Mail, is_staff = True, is_superuser = True, ** kwargs) user.set_password (Passwort) user.save() Benutzer zurückgeben –

+2

Vollständige Anweisungen hier: https://www.fomfus.com/articles/how-to-use-email-as- Benutzername-für-Django-Authentifizierung-Entfernen-der-Benutzername – user2061057