Django 身份验证:self.request.user 在视图集中始终是匿名的
Django auth: self.request.user is always Anonymous in viewset
我试图让服务器只包含 logged-in 用户创建的 return 文档。我正在关注 this post and this one 但登录用户被 return 编辑为 "Anonymous"。
我正在将 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" 的列表,但只能修改他们创建的列表。
我设置了 permissions.AllowAny 因为我希望未登录的用户看到 public 列表。在客户端代码中,我检查用户是否已登录,如果已登录,我会在查询 header.
中发送令牌
请注意 Q object 的使用,这是我找到 return 满足两个条件之一的记录的最简单方法。我在 Django rest framework docs. I eventually found it in the main Django docs.
中找不到任何提及 Q object 的地方
这一切似乎都有效,但如果您发现我做错了什么,请发表评论!我不确定这是否是 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
对于通过 TokenAuthentication
进行身份验证的客户端,令牌密钥应包含在 Authorization
HTTP header 中。 Browseable API 只能通过基本或 Session 身份验证传递用户凭据。要测试您的 API,您需要像 cURL
这样的 HTTP 客户端
curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" <url>
允许对您的视图的任何访问都会在 List.objects.filter(created_by=self.request.user)
为未经授权的用户引发内部服务器错误,而不是 401 Unauthorized
。如果查询集依赖于用户,您应该添加权限 class 以要求用户凭据。
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
我试图让服务器只包含 logged-in 用户创建的 return 文档。我正在关注 this post and this one 但登录用户被 return 编辑为 "Anonymous"。
我正在将 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" 的列表,但只能修改他们创建的列表。
我设置了 permissions.AllowAny 因为我希望未登录的用户看到 public 列表。在客户端代码中,我检查用户是否已登录,如果已登录,我会在查询 header.
中发送令牌请注意 Q object 的使用,这是我找到 return 满足两个条件之一的记录的最简单方法。我在 Django rest framework docs. I eventually found it in the main Django docs.
中找不到任何提及 Q object 的地方这一切似乎都有效,但如果您发现我做错了什么,请发表评论!我不确定这是否是 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
对于通过 TokenAuthentication
进行身份验证的客户端,令牌密钥应包含在 Authorization
HTTP header 中。 Browseable API 只能通过基本或 Session 身份验证传递用户凭据。要测试您的 API,您需要像 cURL
curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" <url>
允许对您的视图的任何访问都会在 List.objects.filter(created_by=self.request.user)
为未经授权的用户引发内部服务器错误,而不是 401 Unauthorized
。如果查询集依赖于用户,您应该添加权限 class 以要求用户凭据。
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