5.0 KiB
Authorization in Django
There are several ways you may want to limit access to data when working with Graphene and Django: limiting which fields are accessible via GraphQL and limiting which objects a user can access.
Let's use a simple example model.
from django.db import models
class Post(models.Model):
= models.CharField(max_length=100)
title = models.TextField()
content = models.BooleanField(default=False)
published = models.ForeignKey('auth.User') owner
Limiting Field Access
To limit fields in a GraphQL query simply use the fields
meta attribute.
from graphene import relay
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
= Post
model = ('title', 'content')
fields = (relay.Node, ) interfaces
conversely you can use exclude
meta attribute.
from graphene import relay
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
= Post
model = ('published', 'owner')
exclude = (relay.Node, ) interfaces
Queryset Filtering On Lists
In order to filter which objects are available in a queryset-based list, define a resolve method for that field and return the desired queryset.
from graphene import ObjectType
from graphene_django.filter import DjangoFilterConnectionField
from .models import Post
class Query(ObjectType):
= DjangoFilterConnectionField(PostNode)
all_posts
def resolve_all_posts(self, info):
return Post.objects.filter(published=True)
User-based Queryset Filtering
If you are using GraphQLView
you can access Django's request with the context argument.
from graphene import ObjectType
from graphene_django.filter import DjangoFilterConnectionField
from .models import Post
class Query(ObjectType):
= DjangoFilterConnectionField(PostNode)
my_posts
def resolve_my_posts(self, info):
# context will reference to the Django request
if not info.context.user.is_authenticated:
return Post.objects.none()
else:
return Post.objects.filter(owner=info.context.user)
If you're using your own view, passing the request context into the schema is simple.
= schema.execute(query, context_value=request) result
Global Filtering
If you are using DjangoObjectType
you can define a custom get_queryset.
from graphene import relay
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
= Post
model
@classmethod
def get_queryset(cls, queryset, info):
if info.context.user.is_anonymous:
return queryset.filter(published=True)
return queryset
Filtering ID-based Node Access
In order to add authorization to id-based node access, we need to add a method to your DjangoObjectType
.
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
= Post
model = ('title', 'content')
fields = (relay.Node, )
interfaces
@classmethod
def get_node(cls, info, id):
try:
= cls._meta.model.objects.get(id=id)
post except cls._meta.model.DoesNotExist:
return None
if post.published or info.context.user == post.owner:
return post
return None
Adding Login Required
To restrict users from accessing the GraphQL API page the standard Django LoginRequiredMixin can be used to create your own standard Django Class Based View, which includes the LoginRequiredMixin
and subclasses the GraphQLView
.:
# views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from graphene_django.views import GraphQLView
class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
pass
After this, you can use the new PrivateGraphQLView
in the project's URL Configuration file url.py
:
For Django 1.11:
= [
urlpatterns # some other urls
r'^graphql$', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
url( ]
For Django 2.0 and above:
= [
urlpatterns # some other urls
'graphql', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
path( ]