Django Rest Framework Пользовательская аутентификация JWT
Я создал приложение Django, в котором я хочу иметь возможность аутентифицировать пользователей, проверяя не только имя пользователя и пароль, но также определенное поле в связанной модели. Тело пользовательского запроса, которое я хочу POST
до конечной точки есть:
payload = { 'username': user, 'password': password, 'app_id': uuid4}
Я использую djangorestframework-simplejwt
модуль для получения токена доступа.
models.py
class Application(models.Model):
app_name = models.CharField(max_length=300)
app_id = models.UUIDField(default=uuid.uuid4, editable=False)
def __str__(self):
return self.app_name
class ProfileApp(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
app = models.ForeignKey(Application, on_delete=models.CASCADE)
expires_on = models.DateTimeField(default=datetime.now() + timedelta(days=15))
def __str__(self):
return self.app.app_name + " | " + self.user.username
Можно ли переопределить TokenObtainPairView
из rest_framework_simplejwt
только аутентифицировать пользователя, если expires_on
дата еще не истекла? Или есть проблема в архитектуре, если сделать это так?
1 ответ
Вы можете сделать это, создав собственный сериализатор, который наследует от TokenObtainPairSerializer
и расширение validate
метод для проверки значений настраиваемых полей. Нет проблем с архитектурой, если вы стараетесь не переопределять необходимую функциональность родительского класса.
Вот пример:
import datetime as dt
import json
from rest_framework import exceptions
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
try:
request = self.context["request"]
except KeyError:
pass
else:
request_data = json.loads(request.body)
username = request_data.get("username")
app_id = request_data.get("app_id")
profile_has_expired = False
try:
profile = ProfileApp.objects.get(user__username=username, app__app_id=app_id)
except ProfileApp.DoesNotExist:
profile_has_expired = True
else:
profile_has_expired = dt.date.today() > profile.expires_on
finally:
if profile_has_expired:
error_message = "This profile has expired"
error_name = "expired_profile"
raise exceptions.AuthenticationFailed(error_message, error_name)
finally:
return super().validate(attrs)
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
Тогда используйте MyTokenObtainPairView
на месте TokenObtainPairView
в вашем файле URL.
Также с User
а также ProfileApp
разделить поле "один на один", похоже, что вы можете избежать использования "app_id
ключ / поле вообще.