Невозможно войти в конечную точку токена с именем пользователя/паролем: drf token auth и пользовательская модель пользователя, Django
У меня есть базовое Django приложение, использующее Django rest framework, пользовательскую модель пользователя, наследующую от модели по умолчанию, и базовую аутентификацию токена.
Я могу сгенерировать токен для любого пользователя, выполнив команду python3 ./manage.py drf_create_token {USERNAME/EMAIL}
, и аутентифицировать с его помощью соответствующие запросы.
Однако, когда я пытаюсь обратиться к конечной точке моего токена (в данном случае http://127.0.0.1:8000/api/token/
, или эквивалент для развернутого приложения), я получаю
{
"non_field_errors": [
"Unable to log in with provided credentials."
]
}
Мое тело запроса (application/json) выглядит так:
{
"username": "test@test.com",
"password": "test"
}
Я убедился, что пользователь активен; что пароль правильный; и что имя пользователя совпадает с электронной почтой.
Мой пользовательский класс:
class Customer(AbstractUser):
first_name = models.CharField(max_length=240)
last_name = models.CharField(max_length=240)
email = models.EmailField(unique=True)
phone_number = PhoneNumberField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
is_active=models.BooleanField(default=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["password", "phone_number", "first_name", "last_name", "username"]
def __str__(self):
return f"{self.first_name} {self.last_name}"
релевантные ссылки:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/users/', include('customer.urls')),
path('api/token/', obtain_auth_token, name="auth_token"),
]
в settings.py у меня есть следующее:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'phonenumber_field',
'customer',
'contact',
'rest_framework',
'rest_framework.authtoken',
]
...
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
...
AUTH_USER_MODEL = 'customer.Customer'
...
Мой сериализатор (здесь контакты представляют собой другую модель):
class CustomerSerializer(serializers.ModelSerializer):
contacts = serializers.SerializerMethodField()
def get_contacts(self, obj):
from contact.serializers import ContactSerializer
from contact.models import Contact
return ContactSerializer(Contact.objects.filter(user=obj), many=True, read_only=True).data
class Meta:
model = Customer
fields = [
'pk',
'first_name',
'last_name',
'email',
'phone_number',
'created_at',
'updated_at',
'contacts',
]
Что я могу упустить? Я уже перепробовал все решения здесь: DRF auth_token: "non_field_errors": ["Невозможно войти в систему с предоставленными учетными данными."
Я нашел проблему - следуя https://docs.djangoproject.com/en/4.0/topics/auth/customizing/#a-full-example я смог увидеть, что при использовании пользовательской модели пользователя, вы должны обновить способ создания пользовательских пользователей (через администратора, auth или другим способом), чтобы убедиться, что пароль хэшируется правильно. Следуя этому, я создал пользовательскую форму администратора и пользовательский менеджер пользователей, который правильно переопределяет и обрабатывает сохранение модели:
def create_user(self, email, first_name, last_name, phone_number, password=None):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
phone_number=phone_number,
)
user.set_password(password)
user.save(using=self._db)
return user