Django Rest Framework Custom Permission не вступает в силу
У меня есть файл permissions.py, который содержит пользовательское разрешение под названием CanViewUserRecord. Я назначил его на набор представлений под названием UserRecordView. Однако разрешение не работает, всякий раз, когда я вызываю конечную точку, прикрепленную к набору представлений, все данные из базы данных возвращаются. Вот код пользовательского разрешения:
from accounts.models import Staff
class CanViewUserRecord(permissions.BasePermission):
edit_methods = ("PUT", "PATCH")
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
if obj.account_type == "staff":
# If user is the manager of staff
if obj.staff.manager == request.user.id:
return True
# If the user is the owner
if obj == request.user:
return True
# Allow admins to access
if request.user.account_type == "admin":
return True
return False
elif obj.account_type == "manager":
# If the user is the owner
if obj == request.user:
return True
# Allow Admins to access
if request.user.account_type == "admin":
return True
return False
elif obj.account_type == "admin":
# If the user is the owner
if obj == request.user:
return True
# Allow Admins to access
if request.user.account_type == "admin":
return True
return False
else:
return False
elif request.method in self.edit_methods:
if obj.account_type == "staff":
if (
request.user.account_type == "manager"
or request.user.account_type == "admin"
):
return True
else:
return False
elif obj.account_type == "manager":
return True
else:
return False
return False
Идея заключается в том, чтобы ограничить то, что пользователи могут видеть, в зависимости от типа_аккаунта пользователя, назначенного токену, переданному в конечную точку API. Вот мой код набора представлений:
class UserRecordView(views.APIView):
"""
API View to create or get a list of all the registered
users. GET request returns the registered users whereas
a POST request allows to create a new user.
"""
permission_classes = [CanViewUserRecord, permissions.IsAuthenticated]
def get(self, format=None):
users = Account.objects.all()
serializer = AccountSerializer(users, many=True)
return response.Response(serializer.data)
def post(self, request):
serializer = AccountSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.save()
return response.Response(serializer.data, status=status.HTTP_201_CREATED)
return response.Response(
{
"error": True,
"error_msg": serializer.error_messages,
},
status=status.HTTP_400_BAD_REQUEST,
)
Итак, если я делаю запрос с токеном, который назначен пользователю, имеющему статус "manager", я не хочу, чтобы он мог видеть записи для пользователя, имеющего тип учетной записи "admin". Однако я провел тест, в котором разрешение просто вернуло False и ничего больше, и запрос API все равно возвращает данные, даже когда разрешение установлено на False. Есть идеи, что я делаю не так? Вот модель для справки о полях:
class Account(auth_models.AbstractBaseUser):
username = models.CharField(max_length=40, unique=True, primary_key=True)
ACCOUNT_TYPE_CHOICES = (
("manager", "Manager"),
("staff", "Staff"),
("admin", "Admin"),
)
account_type = models.CharField(
choices=ACCOUNT_TYPE_CHOICES,
default="staff",
blank=False,
null=False,
max_length=10,
)
date_joined = models.DateTimeField(verbose_name="Date Joined",
auto_now_add=True)
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["account_type"]
objects = AccountManager()
def __str__(self):
return self.username
def has_module_perms(self, app_label):
return True
class Staff(models.Model):
user = models.OneToOneField(Account, on_delete=models.CASCADE, primary_key=True)
first_name = models.CharField(max_length=50, null=False, blank=False)
last_name = models.CharField(max_length=50, null=False, blank=False)
date_of_birth = models.DateField(null=False, blank=False)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
employment_start_date = models.DateField(null=False, blank=True)
employment_end_date = models.DateField(blank=True)
role = models.ForeignKey(
Role, on_delete=models.CASCADE, related_name="assigned_staff"
)
REQUIRED_FIELDS = [
"user",
"first_name",
"last_name",
"date_of_birth",
"manager",
"employment_start_date",
"role",
]
EDIT: Я добавил функцию has_permission в разрешение, как предложил JPG в комментариях. Данные, которые возвращаются, все еще неверны и дают мне доступ к ресурсу, на который у него не должно быть разрешения. Вот обновленный код:
class CanViewUserRecord(permissions.BasePermission):
edit_methods = ("PUT", "PATCH")
message = None
def has_permission(self, request, view):
if request.user.is_authenticated:
return True
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
if obj.account_type == "employee":
# If user is the employer
if obj.employee.employer == request.user.id:
return True
# If the user is the owner
if obj == request.user:
return True
# Allow Jool Admins to access
if request.user.account_type == "jool-admin":
return True
self.message = "Requestor does not have access to this employee record"
return False
elif obj.account_type == "provider":
# If the user is the owner
if obj == request.user:
return True
# Allow Jool Admins to access
if request.user.account_type == "jool-admin":
return True
self.message = "Requestor cannot view provider records"
return False
elif obj.account_type == "jool-admin":
# If the user is the owner
if obj == request.user:
return True
# Allow Jool Admins to access
if request.user.account_type == "jool-admin":
return True
self.message = "Requestor cannot view admin records"
return False
else:
return False
elif request.method in self.edit_methods:
if obj.account_type == "employee":
if (
request.user.account_type == "provider"
or request.user.account_type == "jool-admin"
):
return True
else:
return False
elif obj.account_type == "provider":
return True
else:
return False
return False
Я думаю, это то, что вы ищете whats-the-differences-between-has-object-permission-and-has-permission
has_object_permission(...)
вызывается, когда вы вызываете get_object()
, поэтому вам нужно переопределить has_permission(...)
вместо этого.
Как я вижу:
def has_permission(self, request, view):
if request.user.is_authenticated:
return True
это всегда позволяет пользователю, уже вошедшему в систему, пройти CanViewUserRecord