Разрешения Django-rest-framework для создания в viewet
Я пытаюсь создать REST API и застреваю при регистрации пользователя: в основном мне нужно иметь токен доступа, прежде чем я зарегистрируюсь.
Это представление:
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
def metadata(self, request):
"""
Don't include the view description in OPTIONS responses.
"""
data = super(UserViewSet, self).metadata(request)
return data
def create(self, request):
serializer = self.get_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
self.object.set_password(self.object.password)
self.object.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Это обходной путь:
@api_view(['POST'])
@permission_classes((AllowAny,))
@csrf_exempt
def create_auth(request, format=None):
data = JSONParser().parse(request)
serialized = UserSerializer(data=data)
if serialized.is_valid():
user = User.objects.create_user(
serialized.init_data['email'],
serialized.init_data['username'],
serialized.init_data['password'],
)
user.groups = serialized.init_data['groups']
user.save()
serialized_user = UserSerializer(user)
return Response(serialized_user.data, status=status.HTTP_201_CREATED, headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8000/"})
else:
return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST, headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8000/"})
Мой вопрос: как я могу указать в UserViewSet, что для создания я не требую учетных данных? Или указать собственный метод проверки подлинности? Я не хочу изменять классы проверки подлинности/разрешения для всего вида.
Спасибо,
Adi
ИЗМЕНИТЬ
для уточнения: незарегистрированным пользователям должно быть разрешено регистрировать данные POST, и им не разрешается ничего другого. Аутентифицированные пользователи могут получить список пользователей и обновить свой собственный профиль... это поведение по умолчанию. Вот почему AllowAny имеет не вариант. На мой взгляд, подходящим местом для этого является функция create, но я не понимаю, что я должен отменить.
Ответы
Ответ 1
Настроить метод get_queryset:
def get_queryset(self):
if self.request.user.is_superuser:
return User.objects.all()
else:
return User.objects.filter(id=self.request.user.id)
Таким образом, аутентифицированный пользователь может только извлекать, изменять или удалять свой собственный объект.
Укажите permission_classes = (AllowAny,)
, чтобы аутентифицированный пользователь мог создать новый.
EDIT: дальнейшее объяснение из комментариев
Настройка метода get_queryset таким образом означает следующее:
-
Да, пользователи, не прошедшие проверку подлинности, могут отправлять запрос GET для извлечения списка пользователей, но он будет пустым, поскольку возврат User.objects.filter(id = self.request.user.id) гарантирует, что только информация об аутентифицированном пользователе.
-
То же самое относится к другим методам, если аутентифицированный пользователь пытается УДАЛИТЬ другой объект пользователя, деталь: Не найден будет возвращена (поскольку пользователь, к которому он пытается получить доступ, не находится в наборе запросов).
-
Аутентифицированные пользователи могут делать все, что захотят, для своих пользовательских объектов.
Ответ 2
Вы можете использовать способность Django REST Framework для определения пользовательских разрешений. Вы можете указать как has_permission
, так и has_object_permission
в пользовательском классе. Это даст вам ожидаемое поведение броска 403s для всех пользователей, за исключением публикации в конечной точке создания. Это может выглядеть примерно так:
class IsAnonCreate(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == "POST" and not request.user.is_authenticated():
return True
elif not request.user.is_authenticated() and request.method != "POST":
return False
elif request.method in permissions.SAFE_METHODS:
return True
return False
def has_object_permission(self, request, view, obj):
if not request.user.is_authenticated():
return False
if request.method in permissions.SAFE_METHODS:
return True
return obj.username == request.user.username
Затем вы можете добавить некоторую специальную обработку для аутентифицированных пользователей.
Затем все, что вам нужно сделать, это добавить класс разрешений к вашему ModelViewSet
:
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAnonCreate, )
Ответ 3
Это основано на ответе @argaen, и это сработало для меня:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
permission_classes = (AllowAny,)
authentication_classes = (NoAuthentication,)
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('id', 'email', 'name')
def get_queryset(self):
user = TokenAuthentication().authenticate(self.request)
if user is not None:
user = user[0]
if user.is_superuser:
return get_user_model().objects.all()
else:
return get_user_model().objects.filter(id=user.id)
return get_user_model().objects.none()