2016-05-19 14 views
28

Desidero che Django autentica gli utenti via e-mail, non tramite i nomi utente. Un modo può fornire il valore email come valore del nome utente, ma non lo voglio. Essendo la ragione, ho un url /profile/<username>/, quindi non posso avere un url /profile/[email protected]/.Django - Accedi con e-mail

Un altro motivo è che tutte le e-mail sono uniche, ma a volte capita che il nome utente sia già stato preso. Quindi sto creando automaticamente il nome utente come fullName_ID.

Come posso semplicemente consentire a Django di autenticare con l'e-mail?

Ecco come creo un utente.

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

Questo è il modo di accesso.

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) 

C'è qualche altro di accesso oltre a ottenere il nome utente prima?

risposta

38

È consigliabile scrivere un back-end di autenticazione personalizzato. Qualcosa di simile a questo lavoro:

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 

Poi, set che backend come backend di autenticazione nelle impostazioni:

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

Aggiornato. Eredita da ModelBackend in quanto implementa già metodi come get_user().

+0

Bello. Thxs. Anche la domanda è stata molto utile @PythonEnthusiast. – AlessMascherpa

+0

Errore nel codice: UserMode.DoesNotExist – cyberbudy

+5

Uso di django 1.9.8 Ho un errore: l'oggetto 'EmailBackend' non ha attributo 'get_user'. Risolto aggiungendo il metodo 'get_user' in base a questo http: // StackOverflow.com/a/13954358/2647009 – baltasvejas

2

Avevo un requisito simile in cui il nome utente/email dovrebbe funzionare per il campo del nome utente. Nel caso in cui qualcuno stia cercando il modo di backend di autenticazione, controlla il seguente codice di lavoro. Puoi cambiare il queryset se desideri solo l'email

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 

aggiungere anche AUTHENTICATION_BACKENDS = ('path.to.CustomBackend',) in settings.py

+0

Funziona alla grande per me! – Gui

+0

@GuilhermeJunqueira: fantastico! – anuragb26

2

Si consiglia di personalizzare classe ModelBackend. Il mio codice semplice:

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 

E in settings.py file, aggiungere:

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

Se stai iniziando un nuovo progetto, Django altamente si raccomanda di impostare un costume modello utente. (Vedi https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)

e se l'avete fatto, aggiungere tre linee al modello utente:

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 

Poi opere, mentre authenticate(username=username, password=password) smette di funzionare.

+0

Durante l'esecuzione di createuperuser, questo stesso genera un errore: TypeError: create_superuser() mancante 1 argomento posizionale richiesto: 'username'. È necessario utilizzare il Gestore utente personalizzata: classe '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() utente di ritorno' –

+2

Istruzioni complete qui: https://www.fomfus.com/articles/how-to-use-email-as- nome utente-per-django-autenticazione-rimozione-il-nome utente – user2061057