Django auth: self.request.user всегда является анонимным в viewset - PullRequest
0 голосов
/ 13 января 2019

Я пытаюсь заставить сервер возвращать только те документы, которые были созданы вошедшим в систему пользователем. Я подписан на этот пост и этот , но зарегистрированный пользователь возвращается как "Анонимный".

Я использую Django Rest Framework с Django Rest Auth и пользователь, но без других настроек.

Джанго 2.0.10

Вот мой набор в api.py:

from rest_framework import viewsets, permissions

from .models import List, Item
from .serializers import ListSerializer, ItemSerializer


class ListViewSet(viewsets.ModelViewSet):
    # queryset = List.objects.all()
    # permission_classes = [permissions.AllowAny, ]
    model = List
    serializer_class = ListSerializer

    def get_queryset(self):
        print(self.request.user)
        return List.objects.filter(created_by=self.request.user)

    def pre_save(self, obj):
        obj.created_by = self.request.user

Settings.py:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
}

AUTH_USER_MODEL = 'users.CustomUser'

# django rest auth
ACCOUNT_AUTHENTICATION_METHOD = 'email'

Я читал другие посты об этой проблеме, которые все говорят о пользовательском промежуточном программном обеспечении, но я не создал пользовательское промежуточное программное обеспечение, разве что django-rest-framework или django-rest-auth на самом деле такие вещи? И сообщения, кажется, не показывают, как получить пользователя в наборе.

Также посты старые, поэтому Django, вероятно, изменился.

Из этого поста Я попробовал следующее, не сработало:

class ListViewSet(viewsets.ModelViewSet):
    # queryset = List.objects.all()
    # permission_classes = [permissions.AllowAny, ]
    model = List
    serializer_class = ListSerializer

    def get_queryset(self):
        print(self.request.user)
        self.request.custom_prop = SimpleLazyObject(lambda: get_actual_value(self.request))
        print(self.request.custom_prop)
        return List.objects.filter(created_by=self.request.user)

    def pre_save(self, obj):
        obj.created_by = self.request.user

Я был бы очень благодарен за любую помощь. Это такое основное требование, оно должно быть простым, но я абсолютно застрял.

Редактировать: если это кому-то поможет, ниже приведен мой рабочий код, основанный на ответе Лукаса Вейна. Я расширил логику, чтобы пользователь мог видеть все созданные им списки и все списки, которые имеют флаг «is_public», но могут изменять только созданные им списки.

Я установил разрешения. AllowAny, потому что я хочу, чтобы пользователи, которые не вошли в систему, видели публичные списки. В коде клиента я проверяю, вошел ли пользователь в систему и отправляю ли он токен в заголовке запроса.

Обратите внимание на использование объекта Q, который проще всего найти для возврата записей, удовлетворяющих одному из двух условий. Я не смог найти упоминания об объекте Q в документах Django rest framework . В конце концов я нашел его в основных документах Django .

Кажется, все это работает, но если вы заметили что-то, что я сделал неправильно, пожалуйста, прокомментируйте! Я не уверен, что это подход Django к требованию, но мне нравится тот факт, что логика разрешений находится в одном месте.

from rest_framework import viewsets, permissions
from .models import List
from .serializers import ListSerializer
from django.db.models import Q


class ListViewSet(viewsets.ModelViewSet):
    """
    ViewSet for lists. Before allowing any operation, the user's status is checked.

    Anybody can view a public list.
    A logged-in user can create lists.
    A logged-in user can view, edit and delete the lists they created.
    """
    permission_classes = [permissions.AllowAny, ]
    model = List
    serializer_class = ListSerializer

    def get_queryset(self):
        # restrict any method that can alter a record
        restricted_methods = ['POST', 'PUT', 'PATCH', 'DELETE']
        if self.request.method in restricted_methods:
            # if you are not logged in you cannot modify any list
            if not self.request.user.is_authenticated:
              return List.objects.none()

            # you can only modify your own lists
            # only a logged-in user can create a list and view the returned data
            return List.objects.filter(created_by=self.request.user)

        # GET method (view list) is available to owner and for public lists
        if self.request.method == 'GET':
          if not self.request.user.is_authenticated:
            return List.objects.filter(is_public__exact=True)

          return List.objects.filter(Q(created_by=self.request.user) | Q(is_public__exact=True))

        # explicitly refuse any non-handled methods
        return List.objects.none()

    def pre_save(self, obj):
        obj.created_by = self.request.user

1 Ответ

0 голосов
/ 14 января 2019

Чтобы клиенты проходили аутентификацию через TokenAuthentication, ключ токена должен быть включен в HTTP-заголовок Authorization. Browseable API может передавать учетные данные пользователя только через обычную или сеансовую аутентификацию. Чтобы протестировать API, вам понадобится HTTP-клиент, такой как cURL

curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" <url>

Разрешить любой доступ к вашему представлению вызовет внутреннюю ошибку сервера на List.objects.filter(created_by=self.request.user) для неавторизованных пользователей вместо 401 Unauthorized. Если набор запросов зависит от пользователя, вам нужно добавить класс разрешений, требующий учетные данные пользователя.

class ListViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = ListSerializer

    def get_queryset(self):
        return List.objects.filter(created_by=self.request.user)

    def pre_save(self, obj):
        obj.created_by = self.request.user
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...