has_object_permission方法不起作用Django REST Framework

gab6jxml  于 2023-10-21  发布在  Go
关注(0)|答案(1)|浏览(123)

我想检查我的ModelViewSet,如果用户可以创建邀请其他用户到他的公司。我有四个模型:

# Abstract model TimeStampedModel
class TimeStampedModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        # abstract = True to enable models inherit from TimeStampedModel
        abstract = True

# Custom User model
class User(AbstractUser, TimeStampedModel):
    # Make these fields not to be null
    email = models.EmailField(unique=True, null=False, blank=False)
    first_name = models.CharField(max_length=30, blank=False, null=False)
    last_name = models.CharField(max_length=30, blank=False, null=False)
    image_path = models.ImageField(upload_to='img', default='profile-pic.webp')

    # Assing base user manager for admin panel
    objects = CustomUserManager()

    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = ['email', 'first_name', 'last_name']
# Create your models here.
class Company(TimeStampedModel):
    VISIBILITY_CHOICES = (
        ('hidden', 'Hidden'),
        ('visible', 'Visible for all'),
    )

    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=50, blank=False, null=False, unique=True)
    description = models.TextField(blank=False, null=False)
    visibility = models.CharField(max_length=15, 
                                  choices=VISIBILITY_CHOICES, 
                                  default='visible')

    class Meta:
        verbose_name = "Company"
        verbose_name_plural = 'Companies' # Plural naming

    def __str__(self):
        return self.name    

# Interactions between users and companies
class CompaniesUsers(TimeStampedModel):
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('accepted', 'Accepted'),
        ('revoked', 'Revoked'),
        ('rejected', 'Rejected'),
    )

    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    status = models.CharField(default='pending', choices=STATUS_CHOICES)

    def __str__(self):
        return f"{self.company} - {self.user} - {self.status}"

我创建了自定义权限类,用于检查用户是否可以为该用户创建公司邀请。如果用户不是公司的所有者-则拒绝访问以创建邀请。
我的permissions.py

class IsUsersCompany(BasePermission):
    def has_permission(self, request, view):
        return request.user.is_authenticated
    
    def has_object_permission(self, request, view, obj):        
        return obj.company.owner == request.user

下面是views.py中的ModelViewSet:

class CompaniesUsersModelViewSet(ModelViewSet):
    queryset = CompaniesUsers.objects.all()
    serializer_class = CompaniesUsersModelSerializer
    permission_classes = (IsAuthenticated, )

    def get_permissions(self):
        if self.action == 'create':
            self.permission_classes = (IsUsersCompany, )
        return super().get_permissions()

但是这个权限类不起作用。任何人都可以为另一个用户创建公司邀请,即使该用户不是公司的所有者
我尝试了什么
我尝试使用obj.company直接从Company模型中获取公司ID。我还尝试了在has_permission方法中检查是否请求.method == 'POST'
我希望当我有一个owner_id = 1的company_1,而id为2的用户尝试为另一个用户创建对company_1的邀请时,它会给他一个访问被拒绝的错误。当id为1的用户执行此操作时-它会创建一个新的邀请

djp7away

djp7away1#

问题似乎出在您的IsUsersCompany权限类。您当前正在检查obj.company.owner == request.user。但是,在创建新邀请的上下文中,obj还不存在,因为您正在创建新对象。
若要在创建邀请时强制此权限,您应该重写has_permission方法并检查其中的条件。您需要确保创建邀请的用户是公司的所有者。
以下是如何修改IsUsersCompany类来实现此目的:

from rest_framework import permissions

class IsUsersCompany(permissions.BasePermission):
    def has_permission(self, request, view):
        if view.action == 'create':
            company_id = request.data.get('company')  # Adjust the field name accordingly
            if company_id is not None:
                try:
                    company = Company.objects.get(id=company_id)
                    return company.owner == request.user
                except Company.DoesNotExist:
                    return False  # Return False if the company doesn't exist
        return True  # For other actions, permission is granted

    def has_object_permission(self, request, view, obj):
        return obj.company.owner == request.user

在这段代码中:
在has_permission方法中,我们检查操作是否为'*create'。如果是,我们从请求数据中提取公司ID(确保调整字段名称)。然后我们尝试获取相应的Company对象。如果公司存在,并且其所有者与request.user相同,则返回True。如果公司不存在或者所有者不是request.user,则返回False。对于其他操作,将授予权限。在has_object_permission方法中,可以保留现有的逻辑,检查obj.company.owner是否等于request.user。这确保了用户只能操纵自己的公司。

请确保调整request.data.get('company')中的字段名称,以匹配POST请求数据中使用的名称。

相关问题