PedroBern / django-graphql-auth

Django registration and authentication with GraphQL.

Home Page:https://django-graphql-auth.readthedocs.io/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Protect graphene django "auto" queries and mutations

ckristhoff opened this issue · comments

Prerequisites

  • Is it a bug?
  • Is it a new feature?
  • [ ✅] Is it a a question?
  • Can you reproduce the problem?
  • Are you running the latest version?
  • Did you check for similar issues?
  • Did you perform a cursory search?

Description

Hi, nice work.

I'm trying to private graphene django auto queries and mutations. "Auto" means queries with DjangoObjectType and DjangoFilterConnectionField, and mutations with DjangoModelFormMutation and DjangoFormMutation

The @login_required decorator in graphql_jwt package does not works if resolve method does not exist.

Although the question is an old one, I went through the same problem and maybe other people will, so here is the solution:

For DjangoObjectType and DjangoFilterConnectionField:

class LoginRequiredMixin(object):
	@classmethod
	@login_required
	def get_queryset(cls, queryset, info):
		return queryset

	
class YourType(LoginRequiredMixin, DjangoObjectType):
	...

For DjangoFormMutation:

class LoginRequiredMixin(object):
	@classmethod
	@login_required
	def perform_mutate(cls, form, info):
		form.save()
		return cls(errors=[], **form.cleaned_data)
	
class YourMutation(LoginRequiredMixin, DjangoFormMutation):
	...

For DjangoModelFormMutation:

class LoginRequiredMixin(object):
	@classmethod
	@login_required
	def mutate_and_get_payload(cls, root, info, **input):
		form = cls.get_form(root, info, **input)
	
		if form.is_valid():
			return cls.perform_mutate(form, info)
		else:
			errors = ErrorType.from_errors(form.errors)

		return cls(errors=errors)

class YourMutation(LoginRequiredMixin, DjangoModelFormMutation):
	...

And for SerializerMutation (https://docs.graphene-python.org/projects/django/en/latest/mutations/#django-rest-framework):

from django.shortcuts import get_object_or_404

class LoginRequiredMixin(object):
    @classmethod
    @login_required
    def get_serializer_kwargs(cls, root, info, **input_data):
        lookup_field = cls._meta.lookup_field
        model_class = cls._meta.model_class

        if model_class:
            if "update" in cls._meta.model_operations and lookup_field in input_data:
                instance = get_object_or_404(
                    model_class, **{lookup_field: input_data[lookup_field]}
                )
                partial = True
            elif "create" in cls._meta.model_operations:
                instance = None
                partial = False
            else:
                raise Exception(
                    "Invalid update operation. input_data parameter \"{}\" required.".format(
                        lookup_field
                    )
                )

            return {
                "instance": instance,
                "data": input_data,
                "context": {"request": info.context},
                "partial": partial,
            }

        return {"data": input_data, "context": {"request": info.context}}

class YourMutation(LoginRequiredMixin, SerializerMutation):
	...
errors = ErrorType.from_errors(form.errors)

Here are the imports:

from graphql_jwt.decorators import login_required
from graphene_django.forms.mutation import DjangoFormMutation
from graphene_django.forms.types import ErrorType

@PedroBern is this LoginRequiredMixin appropriate for a PR, if anybody else comes along and wants to pick it up?