【问题标题】:How to check with decorator if user has access to some objects in Django如果用户可以访问 Django 中的某些对象,如何使用装饰器进行检查
【发布时间】:2021-12-30 09:24:42
【问题描述】:

我正在做一个项目,其结构如下。我试图检查用户是否是所请求团队的成员,是否允许查看其详细信息。所以我试图通过装饰器来实现这一点,但我仍然收到 http 500 错误。

我不确定这是否是正确的解决方案和只是糟糕的实施,还是以不同的方式制作更好。

感谢您的帮助。

Team/Models.py

roles = (('admin', 'admin'), ('member', 'member'), ('guest', 'guest'))

class Team(models.Model):
    name = models.CharField(max_length=150)
    description = models.TextField(blank=True)
    members = models.ManyToManyField(User, through='Membership')
    cppTables = models.JSONField(default=list, blank=True)
    
    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return f'teams/{self.pk}/'

    def has_user(self, user_id):
        return self.members.get(pk=user_id).exists()

class Membership(models.Model):
    member = models.ForeignKey(User, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete=models.CASCADE)
    role = models.CharField(max_length=15, choices=roles, default='member')

    def __str__(self):
        return str(self.member)

    class Meta:
        unique_together = [['member', 'team']]

Team/Decorators.py

def required_membership(view_func):
    def wrapper(request, *args, **kwargs):
        team_id = kwargs['team_id']
        team = Team.objects.get(pk=team_id)
        if team.has_user(request.user.id):
            return view_func(request, *args, **kwargs)
        else:
            raise HttpResponseForbidden
    return wrapper

Team/Views.py

@method_decorator(required_membership, name="dispatch")
class TeamDetail(APIView):
    def get_object(self, pk):
        try:
            return Team.objects.get(pk=int(pk))
        except Team.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        team = self.get_object(pk)
        serializer = TeamSerializer(team, many=False)
        return Response(serializer.data)

【问题讨论】:

    标签: django backend decorator


    【解决方案1】:

    在你的装饰器中将包装器放在内部函数中。你的代码看起来像这样,而且不需要把它放在方法装饰器中简单的使用就像这样@required_membership()

    from django.core.exceptions import PermissionDenied
    def required_membership():
        def inner(view_func):
            def wrapper(request, *args, **kwargs):
                team_id = kwargs['team_id']
                team = Team.objects.get(pk=team_id)
                if team.has_user(request.user.id):
                    return view_func(request, *args, **kwargs)
                else:
                    raise PermissionDenied
            return wrapper
    
    
        return inner
    

    更新

    将装饰器放在 get 或 post 方法之上,而不是 class

    【讨论】:

      【解决方案2】:

      最简单的方法可能是只在视图中过滤:

      from django.shortcuts import get_object_or_404
      
      class TeamDetail(APIView):
          
          def get_object(self, pk):
              return get_object_or_404(Team, pk=pk, members=self.request.user)
      
          def get(self, request, pk, format=None):
              team = self.get_object(pk)
              serializer = TeamSerializer(team, many=False)
              return Response(serializer.data)

      如果用户不是团队成员,这将返回 404,当用户打算访问他不是成员的团队时,这将提供更少的信息来利用。

      您也可以通过以下方式检查成员资格来提出HttpResponseForbidden

      from django.shortcuts import get_object_or_404
      
      class TeamDetail(APIView):
          
          def get_object(self, pk):
              team = get_object_or_404(Team, pk=pk)
              if not team.members.filter(pk=self.request.user.pk).exists():
                  raise HttpResponseForbidden
              return team
      
          def get(self, request, pk, format=None):
              team = self.get_object(pk)
              serializer = TeamSerializer(team, many=False)
              return Response(serializer.data)

      您的has_user(…) 方法有一个错误:它应该使用.filter(…),因为模型对象没有.exists() 方法,并且.get(…) 会在找不到项目的情况下引发错误:

      class Team(models.Model):
          # …
      
          def has_user(self, user_id):
              return self.members.filter(pk=user_id).exists()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-15
        • 1970-01-01
        • 2015-09-20
        • 2023-03-25
        • 2016-09-02
        • 2020-08-05
        • 2014-11-03
        • 2020-12-07
        相关资源
        最近更新 更多