如何根据 Graphene/Django 上的用户类型限制对模型的字段访问?
How to limit field access on a model based on user type on Graphene/Django?
假设我有一个模型:
class Employee(models.Model):
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=60)
salary = models.DecimalField(decimal_places=2)
我希望任何人都能够访问 first_name 和 last_name,但只希望某些用户能够读取工资,因为这是机密数据。
然后我想将 write/update 的薪水限制给不同类型的用户。
如何根据请求用户限制字段读取/write/update?
编辑:
这是在 GraphQL API 上下文中。我正在使用石墨烯。我希望在解析器功能中看到可扩展的解决方案。
查询
假设你有
- 查询定义如
employees = graphene.List(EmployeeType)
- 像
这样的查询的解析器
def resolve_employees(self, info, **kwargs):
return Employee.objects.all()
和
- 对名为
can_view_salary
和 can_edit_salary
的 Employee 模型的权限
然后您需要定义 EmployeeType
,其值 salary
取决于用户。像
from graphene_django.types import DjangoObjectType
from myapp.models import Employee
class EmployeeType(DjangoObjectType):
class Meta:
model = Employee
def resolve_salary(self, info):
if info.context.user.has_perm('myapp.can_view_salary'):
return self.salary
return None
重要的一点是,您正在为基于权限值切换的薪水创建自定义 resolve
函数。您不需要为 first_name
和 last_name
.
创建任何其他解析器
突变
Read the documentation first.但是没有更新的例子。
简而言之,您可以采用以下方法:
- 创建一个方法来在您的
Mutation
方法中设置员工
class MyMutations(graphene.ObjectType):
set_employee = SetEmployee.Field()
- 为
SetEmployee
创建一个获取 Employee 对象并更新它的方法。某些用户的工资字段被忽略。
class SetEmployee(graphene.Mutation):
class Arguments:
id = graphene.ID()
first_name = graphene.String()
last_name = graphene.String()
salary = graphene.String()
employee = graphene.Field(lambda: EmployeeType)
@classmethod
def mutate(cls, root, info, **args):
employee_id = args.get('employee_id')
# Fetch the employee object by id
employee = Employee.objects.get(id=employee_id)
first_name = args.get('first_name')
last_name = args.get('last_name')
salary = args.get('salary')
# Update the employee fields from the mutation inputs
if first_name:
employee.first_name = first_name
if last_name:
employee.last_name = last_name
if salary and info.context.user.has_perm('myapp.can_edit_salary'):
employee.salary = salary
employee.save()
return SetEmployee(employee=employee)
注意:最初写这个答案时,Graphene Django 中没有 Decimal 字段可用——我通过将字符串作为输入来避免这个问题。
@MarkChackerian 反应很好。但是,就我个人而言,我认为在未经授权的访问时为字段返回空值可能会产生歧义,因此我个人从这样的 resolve 方法中提出了一个异常:
class UnauthorisedAccessError(GraphQLError):
def __init__(self, message, *args, **kwargs):
super(UnauthorisedAccessError, self).__init__(message, *args, **kwargs)
def resolve_salary(self, info):
if info.context.user.has_perm('myapp.can_view_salary'):
return self.salary
raise UnauthorisedAccessError(message='No permissions to see the salary!')
假设我有一个模型:
class Employee(models.Model):
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=60)
salary = models.DecimalField(decimal_places=2)
我希望任何人都能够访问 first_name 和 last_name,但只希望某些用户能够读取工资,因为这是机密数据。
然后我想将 write/update 的薪水限制给不同类型的用户。
如何根据请求用户限制字段读取/write/update?
编辑:
这是在 GraphQL API 上下文中。我正在使用石墨烯。我希望在解析器功能中看到可扩展的解决方案。
查询
假设你有
- 查询定义如
employees = graphene.List(EmployeeType)
- 像 这样的查询的解析器
def resolve_employees(self, info, **kwargs):
return Employee.objects.all()
和
- 对名为
can_view_salary
和can_edit_salary
的 Employee 模型的权限
然后您需要定义 EmployeeType
,其值 salary
取决于用户。像
from graphene_django.types import DjangoObjectType
from myapp.models import Employee
class EmployeeType(DjangoObjectType):
class Meta:
model = Employee
def resolve_salary(self, info):
if info.context.user.has_perm('myapp.can_view_salary'):
return self.salary
return None
重要的一点是,您正在为基于权限值切换的薪水创建自定义 resolve
函数。您不需要为 first_name
和 last_name
.
突变
Read the documentation first.但是没有更新的例子。
简而言之,您可以采用以下方法:
- 创建一个方法来在您的
Mutation
方法中设置员工
class MyMutations(graphene.ObjectType):
set_employee = SetEmployee.Field()
- 为
SetEmployee
创建一个获取 Employee 对象并更新它的方法。某些用户的工资字段被忽略。
class SetEmployee(graphene.Mutation):
class Arguments:
id = graphene.ID()
first_name = graphene.String()
last_name = graphene.String()
salary = graphene.String()
employee = graphene.Field(lambda: EmployeeType)
@classmethod
def mutate(cls, root, info, **args):
employee_id = args.get('employee_id')
# Fetch the employee object by id
employee = Employee.objects.get(id=employee_id)
first_name = args.get('first_name')
last_name = args.get('last_name')
salary = args.get('salary')
# Update the employee fields from the mutation inputs
if first_name:
employee.first_name = first_name
if last_name:
employee.last_name = last_name
if salary and info.context.user.has_perm('myapp.can_edit_salary'):
employee.salary = salary
employee.save()
return SetEmployee(employee=employee)
注意:最初写这个答案时,Graphene Django 中没有 Decimal 字段可用——我通过将字符串作为输入来避免这个问题。
@MarkChackerian 反应很好。但是,就我个人而言,我认为在未经授权的访问时为字段返回空值可能会产生歧义,因此我个人从这样的 resolve 方法中提出了一个异常:
class UnauthorisedAccessError(GraphQLError):
def __init__(self, message, *args, **kwargs):
super(UnauthorisedAccessError, self).__init__(message, *args, **kwargs)
def resolve_salary(self, info):
if info.context.user.has_perm('myapp.can_view_salary'):
return self.salary
raise UnauthorisedAccessError(message='No permissions to see the salary!')