eamigo86 / graphene-django-extras

Extras functionalities for Graphene-Django
MIT License
417 stars 107 forks source link

How To Subclass DjangoSerializerMutation for a Global @login_required enforcement of JWT #161

Open IdemenB opened 3 years ago

IdemenB commented 3 years ago

Hi all,

I want to protect all mutations and want to use JWT as the authorization method. So I decided to inherit from DjangoSerializerMutation to have variation of it were login_required decorator from the graphql_jwt library is enforced for all create, update and delete method.

from graphene_django_extras import (
    DjangoSerializerMutation,
)
from graphql_jwt.decorators import login_required

class LoginRequiredDjangoSerializerMutation(DjangoSerializerMutation):

    @classmethod
    @login_required
    def create(cls, root, info, **kwargs):
        return super(DjangoSerializerMutation, cls).create(root, info, **kwargs)

    @classmethod
    @login_required
    def update(cls, root, info, **kwargs):
        return super(DjangoSerializerMutation, cls).update(root, info, **kwargs)

    @classmethod
    @login_required
    def delete(cls, root, info, **kwargs):
        return super(DjangoSerializerMutation, cls).delete(root, info, **kwargs)

However, I get the following exception:

Exception: serializer_class is required on all DjangoSerializerMutation

Any ideas or any other suggestion to enforce a global JWT protection for the whole schema?

MariuszBielecki288728 commented 3 years ago

@IdemenB Not sure if you found some solution back then, but for the future readers -- it seems that it can be accomplished by creating a mixin class:

from graphql_jwt.decorators import login_required

class AuthDjangoSerializerMutationMixin():
    @classmethod
    @login_required
    def create(cls, root, info, **kwargs):
        return super().create(root, info, **kwargs)

    @classmethod
    @login_required
    def update(cls, root, info, **kwargs):
        return super().update(root, info, **kwargs)

    @classmethod
    @login_required
    def delete(cls, root, info, **kwargs):
        return super().delete(root, info, **kwargs)

    @classmethod
    def get_serializer_kwargs(cls, root, info, **kwargs):
        return {"context": {"request": info.context}}

And then:

class UserSerializerMutation(
    AuthDjangoSerializerMutationMixin, DjangoSerializerMutation
):
    class Meta:
        description = "DRF serializer based Mutation for Users"
        serializer_class = UserSerializer