Как зарегистрировать пользователя по электронной почте или имени пользователя в Django rest framework (JWT Token)

Я использую:

Django==3.2.9
djangorestframework==3.12.4
djangorestframework-simplejwt==5.0.0

Я хочу сделать систему входа, которая принимает от пользователя имя пользователя или email и пароль в качестве параметра. После этого аутентифицирует пользователя с этими учетными данными и предоставляет доступ & refresh token в качестве ответа.

Я хочу использовать токены доступа и обновления, используя систему токенов JWT из djangorestframework-simplejwt.

Мой простой метод выполнения работы:

Я использую:

Django==3.2.9
djangorestframework==3.12.4
djangorestframework-simplejwt==5.0.0

У меня есть своя пользовательская модель пользователей для дополнительной настройки в соответствии с моими требованиями

В моей пользовательской модели User я определил адрес электронной почты в качестве поля имени пользователя по умолчанию. как показано ниже: USERNAME_FIELD = 'email'

Мои настройки:

in setting.py file

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}


in Urls.py file

urlpatterns = [
    path('token', MyObtainTokenPairView.as_view(), name='token_obtain_pair'),
    # in my case this token route is the login route
]

Теперь у меня есть пользовательское представление входа в систему, названное MyObtainTokenPairView, и оно имеет следующий код:

from .serializers import MyTokenObtainPairSerializer
from rest_framework.permissions import AllowAny
from rest_framework_simplejwt.views import TokenObtainPairView


class MyObtainTokenPairView(TokenObtainPairView):
    permission_classes = [AllowAny]
    serializer_class = MyTokenObtainPairSerializer

Для целей сериализации я использую свой класс сериализатора по умолчанию, который переопределяет класс TokenObtainPairSerializer класса rest_framework_simplejwt Методы класса сериализаторов следующие:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import exceptions

from users.models import Users
from utilities.dataValidation import validateEmail


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)

        token['user_name'] = user.user_name
        token['email'] = user.email

        return token

    def validate(self, attrs):
        userName = attrs.get("email")
        password = attrs.get("password")

        # print("attrs values: ", attrs)

        if validateEmail(userName) is False:
            try:
                user = Users.objects.get(user_name=userName)
                if user.check_password(password):
                    attrs['email'] = user.email
         
                """
                 In my case, I used the Email address as the default Username 
                 field in my custom User model. so that I get the user email 
                 from the Users model and set it to the attrs field. You can 
                 be modified as your setting and your requirement 
                """

            except Users.DoesNotExist:
                raise exceptions.AuthenticationFailed(
                    'No such user with provided credentials'.title()) 
        
        data = super().validate(attrs)
        return data

Для проверки действителен ли email или нет я использую одну функцию следующим образом:

from django.core.validators import validate_email
from django.core.exceptions import ValidationError


def validateEmail(email):
    try:
        validate_email(email)
        return True
    except ValidationError:
        return False

Все эти работы сделаны, я могу сделать вход пользователя, используя email и или UserName пользователя.

simplejwt lib использует authenticate функцию django.

Если вы хотите разрешить пользователю аутентифицироваться как по имени пользователя, так и по электронной почте, вам нужно будет создать собственный бэкэнд аутентификации.

вот пример этого

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q

USER = get_user_model()


class AuthentificationBackend(ModelBackend):
    """
    Define a new authentification backend for auth with username/password or email/password.
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(USER.USERNAME_FIELD)

        case_insensitive_username_field = '{}__iexact'.format(USER.USERNAME_FIELD)
        users = USER._default_manager.filter(
            Q(**{case_insensitive_username_field: username}) | Q(email__iexact=username))

        # Test whether any matched user has the provided password:
        for user in users:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
        if not users:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (see
            # https://code.djangoproject.com/ticket/20760)
            USER().set_password(password)

и затем в своем settings.py

AUTHENTICATION_BACKENDS = [
    # Application custom auth backend
    'path_to.AuthentificationBackend',
]
Вернуться на верх