【问题标题】:How can I set permission for seperate request methods in DRF ModelViewSet?如何在 DRF ModelViewSet 中为单独的请求方法设置权限?
【发布时间】:2020-05-21 16:27:03
【问题描述】:

我对 Django 和 Django Rest Framework 还很陌生,我不知道为什么我的代码不起作用。 我有一个包含几个字段的 Biz 模型:

class Biz(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=200)
    description = models.TextField()
    address = models.CharField(max_length=255, blank=True)
    city = models.CharField(max_length=100)
    phone = PhoneNumberField()

我使用 ModelSerializer 进行序列化:

class BizSerializer(serializers.ModelSerializer):
    class Meta:
        model = Biz
        fields = "__all__"

我使用 ModelViewSet 为其设置一个端点:

class BizViewSet(viewsets.ModelViewSet):
    queryset = Biz.objects.all()
    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = [HasGroupPermission]
    required_groups = {
        "GET": ["__all__"],
        "POST": ["member", "biz_post"],
        "PUT": ["member", "biz_edit"],
        "PATCH": ["member", "biz_edit"],
    }

    serializer_class = BizSerializer

您可能注意到HasGroupPermission。这是我为确认请求用户在所需组中而做出的自定义权限,代码为:

def is_in_group(user, group_name):
    """
    Takes a user and a group name, and returns `True` if the user is in that group.
    """
    try:
        return Group.objects.get(name=group_name).user_set.filter(id=user.id).exists()
    except Group.DoesNotExist:
        return None


class HasGroupPermission(permissions.BasePermission):
    """
    Ensure user is in required groups.
    """

    def has_permission(self, request, view):
        # Get a mapping of methods -> required group.
        required_groups_mapping = getattr(view, "required_groups", {})

        # Determine the required groups for this particular request method.
        required_groups = required_groups_mapping.get(request.method, [])

        # Return True if the user has all the required groups or is staff.
        return all(
            [
                is_in_group(request.user, group_name)
                if group_name != "__all__"
                else True
                for group_name in required_groups
            ]
        ) or (request.user and request.user.is_staff)

但是,当我发出 GET 请求时,权限功能按预期工作,并允许每个人发出请求,而当我发出 POST 请求时,权限功能也可以正常工作(如果用户不在两者中"member" 和 "biz_post" 组合请求被拒绝)。 当我尝试 PUT、PATCH 和 DELETE 等其他方法时,就会出现问题。 为什么会出现这个问题? 一半的方法有效,而另一半(有点)无效。目前我对 DRF 的了解有限,似乎无法解决问题。

【问题讨论】:

  • 那肯定是您的视图集的完整代码?
  • @monio 是的,我的 Biz 视图集仅此而已,除了一些我认为与 BizViewSet 无关的导入和其他模型的视图集(?)。
  • 我建议调试您的 HasGroupPermission.has_permission 方法并确保在“PUT”方法上,required_groups 和 request.method 变量是正确的(您可以调试或仅打印这些信息)。另一种选择是使用 view.action 变量而不是 request.method 进行映射。默认情况下,DRF 分别将 GET(在列表上)、POST、GET(在细节上)、PUT、DELETE 方法映射到 view.action 命名列表、创建、检索、更新、删除。
  • @monio 该功能与 POST 和 GET 请求权限完美配合。我打印了该功能并对其进行了调试。在我眼里没有错。它查询组 id 并检查用户是否在该组中。如果用户不在帖子组中,则只允许 GET。但是,无论指定的组要求如何,所有 PUT、PATCH 和 DELETE 请求都会被拒绝。
  • 您需要调试您的应用程序,也许您没有发送带有 PUT、PATCH 和 DELETE 的身份验证令牌。抱歉,但我认为问题出在其他地方,它应该可以工作。我可以以某种方式与您联系并尝试帮助您(也许可以访问 git repo)。

标签: python django api http django-rest-framework


【解决方案1】:

我意识到我的问题很愚蠢。我的 BizViewSet 实际上是一个 ViewSet,我没有意识到我必须向对象链接发出 PATCH、PUT 和 DELETE 请求(如在 localhost:8000/api/biz/$id 中)。由于我的 User 序列化程序不是 ViewSet,我认为 patch 方法的工作方式与我在 JSON 中传递主键以及我想要修补的数据的方式相同,但 ViewSet 不同,我不知道。傻。

【讨论】:

  • 这不是我最自豪的时刻,但它可能会在未来某个地方成为别人的问题,因为很多人会像我一样在这个讨论中成为新手。
【解决方案2】:

您好,您可以使用 DjangoModelPermissions 代替 HasGroupPermission

(首先你必须导入它)

from rest_framework.permissions import DjangoModelPermissions

此权限检查用户是否具有 PUT、POST 和 DELETE 权限

所有用户都有 GET 权限

您必须在管理员中为用户设置权限或为用户组设置权限

希望对你有帮助

【讨论】:

  • 问题依旧。它适用于 GET 和 POST 请求,但无论组权限、用户权限、超级用户状态和/或 is_staff 状态如何,都不允许使用其他方法。编辑:虽然我认为这种方法要好得多,而且我猜我会有一个更干净的代码。
  • 在 DjangoModelPermissions 中用于 PUT DELETE 和 PATCH 检查用户是否具有权限
  • 我为你测试,效果很好!如果组的用户没有删除或放置或路径的权限。用户不能这样做。
  • 感谢您的努力!那么问题一定是其他的。我会稍微调整一下我的代码,看看是否有任何变化。
  • 如果答案是真的,请接受答案。谢谢
【解决方案3】:

has_permission 方法不提供object-level 权限,而PUTPATCH 需要object-level 权限。

您必须使用permissions.BasePermission 类的has_object_permission 方法创建object-level 权限,仅针对影响特定对象实例的操作运行

看到这个link

希望对你有所帮助。

【讨论】:

  • has_permission 方法总是在视图集初始方法上调用。使用 has_object_permission 没关系(除非您需要访问对象 - 但在这种情况下不需要)
猜你喜欢
  • 2021-03-27
  • 2021-09-26
  • 2020-09-06
  • 1970-01-01
  • 2020-03-02
  • 2012-02-20
  • 1970-01-01
  • 2019-06-01
  • 1970-01-01
相关资源
最近更新 更多