在视图集中创建的 Django-rest-framework 权限
Posted
技术标签:
【中文标题】在视图集中创建的 Django-rest-framework 权限【英文标题】:Django-rest-framework permissions for create in viewset 【发布时间】:2014-05-10 17:03:02 【问题描述】:我正在尝试创建一个 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 中指定 create 我不需要凭据?还是指定自定义身份验证方法?我不想更改整个视图集的身份验证/权限类。
谢谢, 阿迪
编辑 澄清:应允许未注册用户发布注册数据,不应允许其他任何内容。经过身份验证的用户可以获取用户列表并更新他们自己的个人资料……这是默认行为。这就是为什么 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,)
,以便经过身份验证的用户可以创建一个新用户。
编辑:来自 cmets 的进一步解释
以这种方式自定义 get_queryset 方法意味着:
是的,未经身份验证的用户可以发送 GET 请求来检索用户列表,但它将为空,因为返回 User.objects.filter(id=self.request.user.id) 确保只有信息返回关于经过身份验证的用户的信息。
这同样适用于其他方法,如果经过身份验证的用户尝试删除另一个用户对象,则会返回详细信息:未找到(因为它尝试访问的用户不在查询集中)。
经过身份验证的用户可以对其用户对象做任何他们想做的事情。
【讨论】:
感谢您的回复。在这种情况下,我将失去注册用户的所有权限检查和内在功能,例如检索完整的用户列表。 否,因为注册用户只能使用自己的对象而不是其他对象,视图中的 get_queryset 方法确保这一行:return User.objects.filter(id = self. request.user.id)
.
这允许未通过身份验证的用户获取用户列表...我不希望这样。我在原帖中添加了一些说明。
以这种方式自定义 get_queryset 方法意味着以下内容:1 是的,未经身份验证的用户可以发送 GET 请求来检索用户列表,但它会为空 因为return User.objects.filter(id = self.request.user.id)
确保只返回有关经过身份验证的用户的信息。 2 这同样适用于其他方法,如果经过身份验证的用户尝试删除另一个用户对象,则会返回详细信息:未找到(因为它尝试访问的用户不在查询集中)。 3经过身份验证的用户可以为他们的用户对象做任何他们想做的事情。
确实,经过一番思考,这似乎是正确的方法。感谢您的帮助【参考方案2】:
您可以利用 Django REST Framework 定义自定义权限的能力。您可以在自定义类中同时指定 has_permission
和 has_object_permission
。除了发布到创建端点之外,这将为您提供向匿名用户抛出 403 的预期行为。它可能看起来像:
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()
【讨论】:
以上是关于在视图集中创建的 Django-rest-framework 权限的主要内容,如果未能解决你的问题,请参考以下文章
在 Django Rest Framework 中生成 OpenAPI Schema:更新视图集中的 URL 关键字
Google BigQuery:授予服务帐户权限以仅在某些特定数据集中创建作业