Django-이메일로 로그인


84

django가 사용자 이름이 아닌 이메일을 통해 사용자를 인증하기를 원합니다. 한 가지 방법은 이메일 값을 사용자 이름 값으로 제공 할 수 있지만 원하지 않습니다. 이유는 URL /profile/<username>/이 있으므로 URL을 가질 수 없습니다 /profile/abcd@gmail.com/.

또 다른 이유는 모든 이메일이 고유하지만 때때로 사용자 이름이 이미 사용되고 있기 때문입니다. 따라서 사용자 이름을 fullName_ID.

Django가 이메일로 인증하도록 변경하려면 어떻게해야합니까?

이것이 내가 사용자를 만드는 방법입니다.

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

이것이 내가 로그인하는 방법입니다.

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)

사용자 이름을 먼저 얻는 것 외에 다른 로그인이 있습니까?

답변:


103

사용자 지정 인증 백엔드를 작성해야합니다. 다음과 같이 작동합니다.

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

class EmailBackend(ModelBackend):
    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

그런 다음 설정에서 해당 백엔드를 인증 백엔드로 설정합니다.

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

업데이트되었습니다 . 이미 ModelBackend같은 메서드를 구현하므로 상속하십시오 get_user().

https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-an-authentication-backend에서 문서를 참조하십시오.


6
django 1.9.8 사용시 오류가 발생했습니다. 'EmailBackend'개체에 'get_user'속성이 없습니다. 이에 따라 추가 "나 get_user '방법에 의해 해결 stackoverflow.com/a/13954358/2647009
baltasvejas

이 코드가 작동 할 수있는 Django 버전을 지정하십시오. 일부는 get_user 메소드 누락에 대해 불평하고 있습니다.
Younes Henni 박사

2
오히려보다는 다만 if user.check_password(password):당신은 아마 장고를 통해 기본적으로 무엇을 포함 할 ModelBackend: if user.check_password(password) and self.user_can_authenticate(user):사용자가 가지고 있는지 확인하기 위해 is_active=True.
jmq

1
소스 코드에 Django 완화 기능이 포함되어 있지 않으므로 타이밍 공격에 취약하지 않습니까?
Gabriel Garcia

이제 요청 본문에 사용자 이름 및 암호와 같은 필드가 포함되어야합니다. 이메일과 비밀번호로 변경할 수있는 방법이 있습니까?
Karol

55

새 프로젝트를 시작하는 경우 django는 사용자 지정 사용자 모델을 설정하는 것이 좋습니다. ( https://docs.djangoproject.com/en/dev/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project 참조 )

그렇게했다면 사용자 모델에 세 줄을 추가합니다.

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

그런 다음 authenticate(email=email, password=password)작동을 authenticate(username=username, password=password)멈추고 작동합니다.


3
createsuperuser를 실행할 때 자체적으로 오류가 발생합니다. TypeError : create_superuser () missing 1 required positional argument : 'username'. 당신이 사용하는 사용자 정의 사용자 관리에 필요 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
마이클 Holub의

17

1
그런 다음 Django 문서 는 재사용 가능한 앱을 만드는 경우 사용자 지정 사용자 모델을 사용하지 말라고 조언 합니다.
djvg

11

Django 3.x에 대한 이메일 인증

기본 사용자 이름 및 암호 인증 대신 인증을 위해 이메일 / 사용자 이름 및 암호를 사용하려면 다음과 같은 ModelBackend 클래스의 두 가지 메서드 인 authenticate () 및 get_user ()를 재정의해야합니다.

get_user 메소드는 user_id (사용자 이름, 데이터베이스 ID 등 이 될 수 있지만 사용자 개체에 고유해야 함)를 가져 와서 사용자 개체 또는 None을 반환합니다. 이메일을 고유 키로 보관하지 않은 경우 query_set에 대해 반환 된 여러 결과를 처리해야합니다. 아래 코드에서는 반환 된 목록에서 첫 번째 사용자를 반환하여 처리되었습니다.

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

기본적으로 AUTHENTICATION_BACKENDS는 다음과 같이 설정됩니다.

['django.contrib.auth.backends.ModelBackend']

settings.py 파일에서 하단에 다음을 추가하여 기본값을 재정의합니다.

AUTHENTICATION_BACKENDS = ('appname.filename.EmailBackend',)

10

사용자 이름 / 이메일 중 하나가 사용자 이름 필드에서 작동해야하는 유사한 요구 사항이있었습니다. 누군가이 작업을 수행하는 인증 백엔드 방법을 찾고있는 경우 다음 작업 코드를 확인하십시오. 이메일 만 원하는 경우 쿼리 집합을 변경할 수 있습니다.

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

또한 settings.py에 AUTHENTICATION_BACKENDS = ( 'path.to.CustomBackend',)를 추가하십시오.


이것은 1.11에서 2.1.5로 업그레이드 할 때까지 저에게 효과적이었습니다. 이 버전에서 작동하지 않는 이유를 아십니까?
zerohedge

@zerohedge는 인증 메소드의 매개 변수에 요청을 추가합니다. docs.djangoproject.com/en/2.2/topics/auth/customizing/…
Van

또한 타이밍 공격에 노출됩니다. 이러한 취약성을 방지하기 위해 Django 구현을 면밀히 모방하는 것이 좋습니다
Gabriel Garcia

이렇게하면 비활성 사용자도 인증 할 수 있습니다.
Gabriel Garcia

5

장고 2.x

위의 Ganesh가 django 2.x에 대해 언급했듯이 인증 메소드에는 이제 요청 매개 변수가 필요합니다.

# 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)

프로젝트 설정에 백엔드 추가

# settings.py
AUTHENTICATION_BACKENDS = ['path.to.ModelBackend']

사용자 정의 사용자 모델은 활성 및 검증 된 사용자에 대해 고유 한 이메일을 만들어야합니다. 다음과 같이 간단히 수행 할 수 있습니다.

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'

그러나 다른 사람이 다른 사람의 이메일을 사용하지 못하도록 차단하는 것을 방지하려면 이메일 확인을 대신 추가하고 등록 및 로그인 프로세스에서 이메일이 고유하지 않을 수 있다는 점을 고려해야합니다 (그리고 기존의 확인 된 이메일 주소를 사용하는 새 사용자를 방지 할 수 있음).


4

Django 2.X에 대한 이메일 및 사용자 이름 인증

공통 질문은 마음이되는 데, 여기에 모방 정의 구현의 장고 소스 코드는 하지만 인증하는 유지 중 사용자 이름 또는 이메일, 대문자와 소문자를 구별하지 않고로와 사용자 타이밍 공격 보호되지는 비활성 사용자를 인증 .

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

settings.py 올바른 인증 백엔드 를 추가하는 것을 항상 기억하십시오 .


1
UserModel().set_password(password)공격자가 사용자가 존재하는지 여부에 관계없이 거의 동일한 양의 암호화 작업을 수행하여 존재하는지 여부를 판단하지 못하도록 방지 할 수 있는 방법 이 있다는 것을 이해하고 있습니까?
Grand Phuba

1
@GrandPhuba 당신이 완벽하게 맞아요
Gabriel Garcia

2

ModelBackend 클래스를 사용자 정의해야합니다. 내 간단한 코드 :

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

그리고 settings.py 파일에 다음을 추가하십시오.

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

포함하도록 코드 업데이트 request에서 매개 변수 authenticate장고 2.1.1에 대한 방법을
가네

2

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

settings.py에서 다음 줄을 추가하십시오.

AUTHENTICATION_BACKENDS = ['appname.filename.EmailorUsernameModelBackend']

1
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

그리고 다음에서 settings.py:

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

기사 내 장고 - 응용 프로그램이고, backends.py내 응용 프로그램 내부의 파이썬 파일이며, EmailAuthenticate내 안에 인증 백엔드 클래스 backends.py파일


1

아주 간단합니다. 추가 수업이 필요하지 않습니다.

이메일로 사용자를 생성하고 업데이트 할 때 이메일로 사용자 이름 필드를 설정하기 만하면됩니다.

이렇게하면 사용자 이름 필드를 인증 할 때 이메일의 동일한 값이됩니다.

코드:

# 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)

1
답변이 문제 해결에 어떻게 도움이 될 수 있는지 보여주는 샘플 코드를 추가하십시오.
Suit Boy Apps

1
내 대답은 너무 간단해서 분명해야합니다. 귀찮게하지 않습니다. Stackoverflow의 포인트 시스템은 신경 쓰지 않습니다. 여기에 게시하겠습니다 : User.objects.create_user (username = post_data [ 'email'] etc ...)
Casman Ridder

1
@CasmanRidder 추가 정보를 추가하지 않으면 답변이 삭제됩니다.
10 회

omg 내 게시물을 업데이트해야합니다. 그렇지 않으면 내 게시물을 삭제해야합니다. 변경해야합니다 ... 나는 LOL을해야합니다
Casman Ridder


0

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')

답변이 무엇을하고 질문에 답변하는 데 어떻게 도움이되는지 설명하기 위해 약간의 텍스트를 추가 할 수 있습니까?
Jaquez

수정 됨. 감사합니다
Shakil Ahmmed

0

사용자 지정 데이터베이스를 만든 경우 여기에서 이메일 ID와 비밀번호를 확인합니다.

  1. 이메일 ID 및 비밀번호 가져 오기 models.objects.value_list('db_columnname').filter(db_emailname=textbox email)

2. 목록 가져 오기에 할당 object_query_list

3. 목록을 문자열로 변환

예 :

  1. Html Email_idPassword값 가져 오기Views.py

    u_email = request.POST.get('uemail')

    u_pass = request.POST.get('upass')

  2. 데이터베이스에서 이메일 ID와 비밀번호를 가져옵니다.

    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)

  3. Query값 세트 에서 목록의 이메일 ID 및 비밀번호 값을 가져옵니다.

    Email_Value = Email[0]

    Password_Value=Password[0]

  4. 목록을 문자열로 변환

    string_email = ''.join(map(str, Email_Value))

    string_password = ''.join(map(str, Password_Value))

마지막으로 로그인 조건

if (string_email==u_email and string_password ==u_pass)

0

나는 그것을위한 도우미를 만들었다 : function 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

이를 수행하는 방법이 Django 3.0으로 업데이트 된 것 같습니다.

나를위한 작업 방법은 다음과 같습니다.

authentication.py # <-나는 이것을 앱에 넣었습니다 (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

그런 다음 settings.py 파일에 추가했습니다.

AUTHENTICATION_BACKENDS = (
    'appname.authentication.EmailBackend',
)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.