Chcę, aby django uwierzytelniało użytkowników przez e-mail, a nie przez nazwy użytkowników. Jednym ze sposobów może być podanie wartości e-mail jako wartości nazwy użytkownika, ale ja tego nie chcę. Powodem jest to, że mam adres URL /profile/<username>/
, dlatego nie mogę mieć adresu URL /profile/[email protected]/
.
Innym powodem jest to, że wszystkie e-maile są unikalne, ale czasami zdarza się, że nazwa użytkownika jest już zajęta. Dlatego automatycznie tworzę nazwę użytkownika jako fullName_ID
.
Jak mogę po prostu zmienić zezwolenie Django na uwierzytelnianie za pomocą poczty e-mail?
W ten sposób tworzę użytkownika.
username = `abcd28`
user_email = `[email protected]`
user = User.objects.create_user(username, user_email, user_pass)
Tak się loguję.
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)
Czy istnieje inny sposób logowania oprócz uzyskania nazwy użytkownika w pierwszej kolejności?
if user.check_password(password):
prawdopodobnie chcesz to co robi Django domyślnie poprzezModelBackend
:if user.check_password(password) and self.user_can_authenticate(user):
w celu sprawdzenia, czy użytkownik mais_active=True
.Jeśli zaczynasz nowy projekt, django zdecydowanie zaleca skonfigurowanie niestandardowego modelu użytkownika. (patrz https://docs.djangoproject.com/en/dev/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project )
a jeśli to zrobiłeś, dodaj trzy linie do swojego modelu użytkownika:
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
Wtedy
authenticate(email=email, password=password)
działa, aauthenticate(username=username, password=password)
przestaje działać.źródło
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
Uwierzytelnianie poczty elektronicznej dla Django 3.x
Aby użyć adresu e-mail / nazwy użytkownika i hasła do uwierzytelniania zamiast domyślnej nazwy użytkownika i hasła, musimy zastąpić dwie metody klasy ModelBackend: autenticate () i get_user ():
Metoda get_user przyjmuje identyfikator_użytkownika - który może być nazwą użytkownika, identyfikatorem bazy danych lub czymkolwiek, ale musi być unikalny dla obiektu użytkownika - i zwraca obiekt użytkownika lub None. Jeśli nie zachowałeś e-maila jako unikalnego klucza, będziesz musiał zadbać o wiele wyników zwracanych dla query_set. W poniższym kodzie zadbano o to, zwracając pierwszego użytkownika ze zwróconej listy.
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
Domyślnie AUTHENTICATION_BACKENDS jest ustawione na:
['django.contrib.auth.backends.ModelBackend']
W pliku settings.py dodaj następujący u dołu, aby zastąpić ustawienie domyślne:
AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)
źródło
Miałem podobny wymóg, w którym nazwa użytkownika / adres e-mail powinny działać w polu nazwy użytkownika.Jeśli ktoś szuka sposobu uwierzytelniania, aby to zrobić, sprawdź następujący kod roboczy.Możesz zmienić zestaw zapytań, jeśli chcesz tylko 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
Dodaj również AUTHENTICATION_BACKENDS = ('path.to.CustomBackend',) w settings.py
źródło
Django 2.x
Jak wspomniano powyżej przez Ganesh dla django 2.x, metoda uwierzytelniania wymaga teraz parametru żądania.
# 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)
dodaj backend do ustawień projektu
# settings.py AUTHENTICATION_BACKENDS = ['path.to.ModelBackend']
Twój niestandardowy model użytkownika będzie musiał tworzyć unikalne wiadomości e-mail dla aktywnych i zweryfikowanych użytkowników. Możesz to zrobić za pomocą czegoś takiego:
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'
Aby jednak uniemożliwić komuś blokowanie korzystania z adresu e-mail przez inną osobę, należy zamiast tego dodać weryfikację adresu e-mail, a proces rejestracji i logowania wziąć pod uwagę, że wiadomości e-mail mogą nie być unikalne (i prawdopodobnie uniemożliwić nowym użytkownikom korzystanie z istniejącego i zweryfikowanego adresu e-mail).
źródło
Uwierzytelnianie adresu e-mail i nazwy użytkownika dla Django 2.X
Mając na uwadze, że jest to częste pytanie, oto niestandardowa implementacja naśladująca kod źródłowy Django, ale która uwierzytelnia użytkownika za pomocą nazwy użytkownika lub adresu e-mail, bez rozróżniania wielkości liter, zachowując ochronę przed atakami czasowymi i nie uwierzytelniając nieaktywnych użytkowników .
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
Zawsze pamiętaj, aby dodać to swoje settings.py do właściwego zaplecza uwierzytelniania .
źródło
UserModel().set_password(password)
ma to na celu uniemożliwić atakującym określenie, czy użytkownik istnieje, czy nie, wykonując mniej więcej taką samą ilość pracy kryptograficznej, niezależnie (zakładam, że jest to atak czasowy, o którym mowa)?Należy dostosować klasę ModelBackend. Mój prosty kod:
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
A w pliku settings.py dodaj:
AUTHENTICATION_BACKENDS = ['path.to.class.YourBackend']
źródło
request
parametr wauthenticate
metodzie dla django 2.1.1Uwierzytelnianie za pomocą adresu e-mail i nazwy użytkownika Dla 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
W settings.py dodaj następujący wiersz,
AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']
źródło
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
A potem w
settings.py
:gdzie artykuły to moja aplikacja django,
backends.py
to plik Pythona w mojej aplikacji iEmailAuthenticate
klasa zaplecza uwierzytelniania w moimbackends.py
plikuźródło
Dość proste. Nie ma potrzeby prowadzenia dodatkowych zajęć.
Podczas tworzenia i aktualizowania użytkownika za pomocą adresu e-mail, po prostu ustaw pole nazwy użytkownika na adres e-mail.
W ten sposób podczas uwierzytelniania pole nazwy użytkownika będzie miało tę samą wartość co e-mail.
Kod:
# 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)
źródło
W przypadku Django 2
username = get_object_or_404(User, email=data["email"]).username user = authenticate( request, username = username, password = data["password"] ) login(request, user)
źródło
Uwierzytelnianie za pomocą poczty elektronicznej Dla 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')
źródło
Jeśli utworzyłeś niestandardową bazę danych, stamtąd, jeśli chcesz zweryfikować swój identyfikator e-mail i hasło.
models.objects.value_list('db_columnname').filter(db_emailname=textbox email)
2. przypisanie na liście zostało pobrane
object_query_list
3. Konwertuj listę na ciąg
Np .:
Weź kod HTML
Email_id
iPassword
wartościViews.py
u_email = request.POST.get('uemail')
u_pass = request.POST.get('upass')
Pobierz identyfikator e-mail i hasło z bazy danych
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)
Weź identyfikator e-mail i wartości hasła z listy z
Query
zestawu wartościEmail_Value = Email[0]
Password_Value=Password[0]
Konwertuj listę na ciąg
string_email = ''.join(map(str, Email_Value))
string_password = ''.join(map(str, Password_Value))
Wreszcie twój warunek logowania
if (string_email==u_email and string_password ==u_pass)
źródło
Stworzyłem do tego pomocnika: funkcję
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)
źródło
Wygląda na to, że metoda robienia tego została zaktualizowana w Django 3.0.
Metodą pracy jest dla mnie:
authentication.py # <- umieściłem to w aplikacji (nie działało w folderze projektu obok 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
Następnie dodałem to do pliku settings.py
źródło
Domyślny model użytkownika dziedziczy / rozszerza klasę abstrakcyjną. Ramy powinny być łagodne dla pewnej liczby zmian lub zmian.
Prostszym sposobem jest wykonanie następujących czynności: To jest w środowisku wirtualnym
LINIA 336 w atrybucie e-mail dodaj unikalny i ustaw ją na wartość true
email = models.EmailField(_('email address'), blank=True,unique=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username']
Robisz to na własne ryzyko,
źródło