Set permissions on Graphene Relay Node and Connection fields

985 views Asked by At

How can I require authentication/authorization on the tier Node field and allTiers Connection field query below?

# schema.py
class TierNode(DjangoObjectType):
    class Meta:
        model = Tier
        filter_fields = []
        interfaces = (graphene.relay.Node,)


class Query(graphene.ObjectType):
    tier = relay.Node.Field(TierNode)
    all_tiers = DjangoFilterConnectionField(TierNode)
2

There are 2 answers

2
Jerven Clark On

You can define a resolver for those fields with auth decorator like so:

from graphql_jwt.decorators import login_required

class Query(graphene.ObjectType):
    tier = relay.Node.Field(TierNode)
    all_tiers = DjangoFilterConnectionField(TierNode)


    @login_required
    def resolve_tier(root, info, **kwargs):
        # code for resolving here

This is just using the login_decorator that comes with graphql_jwt but it will work for your custom decorators too if you defined them.

Furthermore, this also works for when you're resolving a field for TierNode:

class TierNode(DjangoObjectType):
    class Meta:
        model = Tier
        filter_fields = []
        interfaces = (graphene.relay.Node,)

    some_property = graphene.Field("types.SomePropertyType")

    @login_required
    def resolve_some_property(root, info, **kwargs):
        # code for resolving here

1
jorzel On

You can define authorization or/and authentication decorator like this:

from functools import wraps

def authorize_required(role):
    def decorator(func):
        @wraps(func)
        def wrapper(instance, info, *args, **kwargs):
            current_user = info.context.user
            if not current_user.is_authenticated:
                raise Exception("Authentication credentials were not provided")
            if not authorize(instance, current_user, role):
                raise Exception(
                    f"{current_user} has no access to {instance} with required {role=}"
                )
            return func(instance, info, *args, **kwargs)
        return wrapper
    return decorator

def authorize(instance, user, role) -> bool:
   # check if user can have access to instance
   # if there is requirement to have certain role

And use it in schema definition:

class TierNode(DjangoObjectType):
    class Meta:
        model = Tier
        filter_fields = []
        interfaces = (graphene.relay.Node,)


class Query(graphene.ObjectType):
    tier = relay.Node.Field(TierNode)
    all_tiers = DjangoFilterConnectionField(TierNode)
  
    @authorize_required('user')
    def resolve_tier(self, info, **args):
        # some resolve code

    @authorize_required('admin')
    def resolve_all_tiers(self, info, **args):
        # some resolve code