Проверка подлинности Django drf simple-jwt "detail": "Не найдена активная учетная запись с данными учетными данными"
Я реализую аутентификацию пользователя с помощью django-rest_framework_simple-jwt с пользовательским пользователем, My models.py:
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(null=False, unique=True)
username = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username",]
Итак, я реализую аутентификацию restframework simple-jwt, мои настройки.py выглядят следующим образом:
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]}
мой urls.py:
urlpatterns = [
url(r'^api/token/$', TokenObtainPairView.as_view(), name='token_obtain_pair'),
url(r'^api/token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),]
при входе в систему возвращается ошибка, "detail": "No active account found with the given credentials"
все мои пользователи были активны. Я понятия не имею, чтобы разобраться с этим, мне нужна помощь. Спасибо заранее.
11 ответов
Убедитесь, что ваш пароль хешируется, прежде чем он будет сохранен в вашей базе данных. Я столкнулся с той же проблемой и обнаружил, что мои пароли хранились в виде обычного текста. Добавление следующего в мой UserSerializer решило проблему
from django.contrib.auth.hashers import make_password
def validate_password(self, value: str) -> str:
"""
Hash value passed by user.
:param value: password of a user
:return: a hashed version of the password
"""
return make_password(value)
Либо вы не создали суперпользователя для своего приложения Django, либо вам предоставлены неправильные учетные данные для аутентификации
Также убедитесь,
is_active = True
для пользовательского объекта, который вы сохраняете в своем сериализаторе, потому что
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['fullname', 'username', 'email', 'password']
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
# Adding the below line made it work for me.
instance.is_active = True
if password is not None:
# Set password does the hash, so you don't need to call make_password
instance.set_password(password)
instance.save()
return instance
Примечание (согласно документам)
Декоратор login_required НЕ проверяет флаг is_active для пользователя, но AUTHENTICATION_BACKENDS по умолчанию отклоняет неактивных пользователей.
Кажется, моя ошибка была вызвана
write_only
параметр в поле моего пароля
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password']
Удалил это:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6)
class Meta:
model = User
fields = ['email', 'username', 'password']
а потом было все солнце и радуга после этого:-)
Ваш пароль должен быть хеширован, это не должна быть обычная строка
#import make_password
from django.contrib.auth.hashers import make_password
make_password(password)
импортируйте make_password и хешируйте пароль при регистрации...
Вам следует create new superuser account
после настройки JWT authentication
тогда используйте это account
к get the token
python manage.py createsuperuser
Вы не забыли установить в настройках:
AUTH_USER_MODEL = 'your_app_name.User'
попробуй это
from django.contrib.auth.hashers import make_password
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(make_password(password))
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
Я столкнулся с аналогичной проблемой. Оказывается, я не включил поле пароля среди полей сериализатора Writer.
До того, как у меня был такой код;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
Затем я добавил поле пароля, чтобы иметь это;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'password',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
Таким образом, в базе данных сохранялось какое-то другое значение, которое не было паролем, который я добавил. Таким образом, возникает эта ошибка, потому что пароль, который вы указываете в качестве ввода, не соответствует тому, что находится в базе данных. Убедитесь, что сериализатор правильный
Снизился вручную с PyJWT == 2.0.0 до PyJWT == 1.7.1 и решил нашу проблему
pip install PyJWT==1.7.1
Мы используем djangorestframework == 3.12.1 и djangorestframework-simplejwt == 4.4.0 в файле requirements.txt, что автоматически дало нам зависимость от версии 2.0.0.
На мой взгляд, существует проблема, когда для сериализатора предоставляются адрес электронной почты и имя пользователя, но в качестве имени пользователя для аутентификации ожидается электронное письмо. У меня тоже была такая же ошибка. Я также создал своего рода специального пользователя и попытался войти в систему, чтобы получить пару веб-токенов json. Но я использовал только электронную почту, а не имя пользователя. То, что я сделал в итоге, у меня работает. Возможно, этот пример что-то объясняет в том месте, где выполняется аутентификация ...
Модель и менеджер нравятся этой:
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import (
AbstractBaseUser,
BaseUserManager
)
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from rest_framework_simplejwt.tokens import RefreshToken
class CustomUserManager(BaseUserManager):
def get_or_create(self, email=None, **kwargs):
allowed_kwargs = ['first_name', 'last_name', 'img', 'about']
if email is not None:
try:
user_obj = super(CustomUserManager, self).get(email=email)
if kwargs:
for k, v in kwargs.items():
setattr(user_obj, k, v)
user_obj.save()
except ObjectDoesNotExist:
email = self.normalize_email(email)
user_obj = self.model(email=email)
password = kwargs.pop('password', None)
if password is not None:
user_obj.set_password(password)
if kwargs:
for k, v in kwargs.items():
if k in allowed_kwargs:
setattr(user_obj, k, v)
user_obj.save()
else:
return False
return user_obj
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), null=True, unique=True)
first_name = models.CharField(max_length=150, null=True, blank=True)
last_name = models.CharField(max_length=150, null=True, blank=True)
img = models.URLField(null=True, blank=True)
about = models.TextField(_('about'), max_length=500, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return f'<CustomUser(id={self.id} - email={self.email})>'
class Meta:
ordering = ['-created_at']
@property
def full_name(self):
if hasattr(self, 'first_name') and hasattr(self, 'last_name'):
return f'{self.first_name} {self.last_name}'
return 'No fullname'
@property
def jwt_tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
Настройка сериализатора токенов:
from django.contrib.auth import authenticate
from django.contrib.auth.models import update_last_login
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
class CustomTokenSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
def validate(self, email, password):
try:
self.user = CustomUser.objects.get(email=email)
except ObjectDoesNotExist as e:
message = {'error': f'User with email={email} does not exist.'}
return message
check_auth = authenticate(username=email, password=password)
if check_auth is None:
message = {'error':
'The user exists, but the password is incorrect.'}
return message
data = self.user.jwt_tokens
update_last_login(None, self.user)
return data
URL:
urlpatterns += [
path('login/token/', views.LoginTokenView.as_view(), name='login-token')
]