I want to require django's user authentication in order to access the graphql
view.
My first attempt was to decorate the view with login_required
:
from django.contrib.auth.decorators import login_required
from django.urls import path
urlpatterns = [
path("graphql/sync", login_required(GraphQLView.as_view(schema=schema))),
path("graphql", login_required(AsyncGraphQLView.as_view(schema=schema))),
]
It work for the sync view but not for the async one since login_required does not async aware.
For now I endend-up to write my own view which copy the login_required behavior:
from urllib.parse import urlparse
from asgiref.sync import sync_to_async
from strawberry.django.views import AsyncGraphQLView
from django.conf import settings
from django.contrib.auth.views import redirect_to_login
from django.shortcuts import resolve_url
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class LoginRequiredAsyncGraphQLView(AsyncGraphQLView):
@method_decorator(csrf_exempt)
async def dispatch(self, request, *args, **kwargs):
is_authenticated = await sync_to_async(lambda: request.user.is_authenticated)()
if not is_authenticated:
path = request.build_absolute_uri()
resolved_login_url = resolve_url(settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if (not login_scheme or login_scheme == current_scheme) and (
not login_netloc or login_netloc == current_netloc
):
path = request.get_full_path()
return redirect_to_login(path, resolved_login_url)
return await super().dispatch(request, *args, **kwargs)
# urls.py
urlpatterns = [
path("graphql", LoginRequiredAsyncGraphQLView.as_view(schema=schema)),
]
But it seems to not be a nice solution and I bet there is something cleaner.
There is a better solution to have a login_required
decorator compatible with async view ?