How to limit field access on a model based on user type on Graphene/Django?

南笙酒味 提交于 2019-12-12 08:02:30

问题


Let's say I have a model:

class Employee(models.Model):
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=60)
    salary = models.DecimalField(decimal_places=2)

I want anyone to be able to access first_name and last_name but only want certain users to be able to read salary because this is confidential data.

And then I want to restrict write/update for salary to an even different kind of user.

How do I restrict field read/write/update depending on the request user?

EDIT:

This is in the GraphQL API context. I am using Graphene. I'd like to see a scalable solution in the resolver function.


回答1:


QUERIES

Assuming that you have

1) a query defined like

employees = graphene.List(EmployeeType)

2) a resolver for the query like

def resolve_employees(self, info, **kwargs):
    return Employee.objects.all()

and

3) permissions on your Employee model called can_view_salary and can_edit_salary

Then you'll need to define the EmployeeType with a value of salary that is dependent on the user. Something like

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

The important takeaway is that you're creating a custom resolve function for the salary that is switching based on the value of a permission. You don't need to create any other resolvers for first_name and last_name.

(IMPORTANT NOTE: There is NO standard Decimal type in graphene-python, so you have a different problem that I am ignoring here.)




MUTATIONS

Read the documentation first. But there isn't an example for doing an update.

In brief, here's the approach that you can take:

1) Create a method to set the employee in your Mutation method

class MyMutations(graphene.ObjectType):
     set_employee = SetEmployee.Field()

2) Create a method for SetEmployee that gets the Employee object and updates it. The salary field is ignored for certain users. Note again that I am ignoring the Decimal issue by taking a string as an input.

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)



回答2:


Great response @MarkChackerian. However personally, I believe that returning a null value for a field on unauthorised access can be ambiguous, so I personally raise an exception from resolve method like that:

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!')


来源:https://stackoverflow.com/questions/49084322/how-to-limit-field-access-on-a-model-based-on-user-type-on-graphene-django

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!