Как зарегистрировать пользователя по электронной почте или имени пользователя в 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',
]