Django auth:self.request.user在视图集中始终是匿名的

时间:2019-01-13 18:32:28

标签: django authentication filter django-rest-framework django-rest-auth

我试图使服务器仅返回由登录用户创建的文档。我正在关注this postthis one,但已登录的用户返回为“匿名”。

我正在将Django Rest Framework与Django Rest Auth和一个自定义用户一起使用,但没有其他自定义项。

Django 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可能已经改变了。

this post中,我尝试了以下操作,但没有成功:

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

非常感谢您的帮助。这是一个基本的要求,应该很简单,但我绝对受阻。

编辑:如果可以帮助其他人,以下是我基于Lucas Weyne的回答的工作代码。我扩展了逻辑,以便用户看到他们创建的所有列表,以及所有带有标志“ is_public”的列表,但只能修改他们创建的列表。

我设置了权限。AllowAny,因为我希望未登录的用户查看公共列表。在客户端代码中,我检查用户是否已登录,以及是否已在查询标头中发送令牌。

请注意Q对象的使用,这是我发现返回满足两个条件之一的记录的最简单方法。我在Django rest framework docs中找不到关于Q对象的任何提及。我最终在main Django docs中找到了它。

这一切似乎都奏效,但是如果您发现我做错了什么,请发表评论!我不确定这是否是满足要求的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 :(得分:1)

要使客户端通过TokenAuthentication进行身份验证,令牌密钥应包含在Authorization HTTP标头中。可浏览的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