django - Django DRF 创建相关对象的权限
问题描述
我努力在 Django REST 框架上执行对象创建的安全性。
基本上,我可以使用 'has_object_permission' 在对象级别强制执行安全性:登录用户必须是对象的所有者才能操作它。实际上,如文档中所述,我缩小了查询集中的对象检索范围,因此,我得到了 404 而不是 403。我认为这不是问题(更好,因为它隐藏了对象的存在)
但我没有成功禁止其他用户创建相关对象....
我使用 ModelSerializer 和 ModelViewSet。
这里有一些天真的片段:
模型.py:
class Daddy(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=20)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Kiddy(models.Model):
title = models.CharField(max_length=12)
daddy = models.foreignKey(Daddy, on_delete=models.CASCADE)
序列化程序.py:
class KiddySerializer(serializers.ModelSerializer):
class Meta:
model = Kiddy
fields = '__all__'
视图集.py:
class KiddyViewSet(viewsets.ModelViewSet):
serializer_class = KiddySerializer
queryset = User.objects.none()
permission_classes = (IsAuthenticated, IsOwner, )
def get_queryset(self):
dad_uuid = self.kwargs['dad']
return Kiddy.objects.filter(daddy__pk=dad_uuid).filter(daddy__owner=self.request.user)
路由器.py:
router = routers.DefaultRouter()
router.register(r'dad', KiddyViewSet, base_name='kid')
urls.py:
path('api/<uuid:cv>/', include(router.urls))
使用这些 url 访问对象: http://..../api/4ecddcdd-1c0a-4d0b-8254-b0c0d2607e6d/ ---> 列出所有孩子
http://..../api/4ecddcdd-1c0a-4d0b-8254-b0c0d2607e6d/1 ---> 对象孩子
实际上,因为我使用 uuid,所以我得到了一些安全性,这很难猜到......
权限.py:
class IsOwner(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
if request.user != obj.daddy.owner:
return False
else:
return True
如果用错误的所有者登录,我可以创建相关的孩子对象!
我想,我必须以“has_permission”类型实现此权限。但我不知道如何访问那里的对象,因为参数是请求和视图......
在这里,他找到了解决办法。但这根本不是通用的,因为我需要每个相关对象的自定义权限......而且我得到了很多! 检查 Django REST Framework 中相关对象的权限
任何想法?
解决方案
好的,我解决了这个问题:-)
在 permissions.py 中,我怀疑我必须这样做,我添加了这个 'has_permission' :
class IsOwnerParent(permissions.BasePermission):
def has_permission(self, request, view):
daddy = Daddy.objects.get(pk=view.kwargs['dad'])
return daddy.owner == request.user
并将其添加到我的 ModelViewSet 类中:
class KiddyViewSet(viewsets.ModelViewSet):
serializer_class = KiddySerializer
queryset = User.objects.none()
permission_classes = (IsAuthenticated, IsOwner, IsOwnerParent)
def get_queryset(self):
dad_uuid = self.kwargs['dad']
return Kiddy.objects.filter(daddy__pk=dad_uuid).filter(daddy__owner=self.request.user)
因此,实际上此处提供的解决方案Check permissions on a related object in Django REST Framework 确实有效。它实际上非常通用,因为我的许多对象都与“爸爸”对象有关。
实际上,现在检索对象列表的行为看起来更“正常”:我得到 403 错误而不是 404。
我认为这个用例很常见:用户只能创建与他们拥有的对象相关的对象,他们也只能更新和删除他们拥有的对象。
但也许它可以做得更好?
推荐阅读
- go - 如何使取消构建键绑定起作用
- django - 在 Django 应用程序的容器实例中未读取 S3 存储桶的 Heroku 环境变量
- node.js - 如何为服务器生成 vapid-keys?
- python - UnboundLocalError:在 Python 中赋值之前引用了局部变量“x”
- kubernetes - Kubernetes 内存请求和限制定点与二次幂
- excel - 在 VBA 中翻译文本 - 阿拉伯语
- pandas - 我想在 pandas Dataframe 中使用 shift 函数来归档缺失值
- postgresql - 使用 @Transactional(readOnly=true) 时延迟增加
- bash - 在子 shell 中编辑全局变量
- express - 快速错误处理无法正常工作