Вітаю на одній з найцікавіших і найкорисніших лекцій на нашому шляху до створення просунутого і безпечного GraphQL API. Сьогодні ми розберемо, як керувати доступом до даних, забезпечувати безпеку запитів та інтегрувати вбудовану систему аутентифікації Django у твій GraphQL проєкт.
На минулих лекціях ми познайомились з основами GraphQL, вивчили його основні переваги та відмінності від REST API. Ми встановили і налаштували Graphene-Django, створили першу схему (schema) і розібрались із запитами (queries) та мутаціями (mutations). Більше того, ми інтегрували Django моделі з GraphQL, використовуючи DjangoObjectType. Наш GraphQL API вже вміє повертати та змінювати дані з бази, але ми поки що не обмежували доступ до них для різних користувачів. Час це виправити!
Безпека та аутентифікація в GraphQL
Будь-який веб-додаток, чи то REST або GraphQL API, потребує захисту. Ми повинні контролювати, хто має доступ до даних, і обмежувати це залежно від ролі чи статусу користувача.
- Навіщо потрібна аутентифікація в GraphQL?
Уяви, що твій GraphQL API — це двері в твій дім. Аутентифікація — це ключ, який підтверджує, що "цей користувач має право увійти". Без ключа сторонні можуть отримати доступ до даних, які їм не належать, а це, м'яко кажучи, погана ідея.
- Як працює система аутентифікації в Django?
Django надає вбудовану систему аутентифікації, засновану на моделі User. До неї входять такі функції, як вхід у систему, вихід, управління користувачами та перевірка їхніх прав.
Graphene-Django прекрасно інтегрується з цією системою, надаючи нам інструменти для перевірки аутентифікованості запитів.
Інтеграція аутентифікації Django з GraphQL
Почнемо зі звичного сценарію: нам потрібно обмежити доступ до деяких запитів і мутацій лише для аутентифікованих користувачів. Давай розберемося, як це зробити.
Встановлення GraphQLAuth (опціонально)
Якщо ти хочеш пришвидшити процес інтеграції аутентифікації, встанови бібліотеку django-graphql-auth. Вона додає підтримку реєстрації, входу, виходу, зміни пароля та багато іншого "з коробки".
pip install django-graphql-auth
pip install django-graphql-jwt # для обробки JWT токенів
pip install django-filter
Оновимо налаштування проєкту у settings.py:
INSTALLED_APPS += [
"graphql_auth",
"graphql_jwt.refresh_token",
"django_filters",
]
AUTHENTICATION_BACKENDS = [
"graphql_jwt.backends.JSONWebTokenBackend",
"django.contrib.auth.backends.ModelBackend",
]
GRAPHENE = {
"SCHEMA": "your_project.schema.schema",
"MIDDLEWARE": [
"graphql_jwt.middleware.JSONWebTokenMiddleware",
],
}
Тепер можна додати стандартний набір мутацій для аутентифікації:
import graphql_jwt
import graphql_auth.schema
from graphene import ObjectType
class AuthMutation(graphql_auth.schema.Mutation, ObjectType):
pass
class Mutation(AuthMutation, ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
class Query(graphql_auth.schema.Query, ObjectType):
pass
Ти щойно додав GraphQL мутації для отримання JWT токенів та перевірки їхньої дійсності.
Обмеження доступу за допомогою @login_required
Graphene надає простий декоратор @login_required, який можна використовувати для обмеження доступу до конкретних запитів або мутацій.
Приклад:
from graphene import Mutation, String
from graphql_jwt.decorators import login_required
class ProtectedMutation(Mutation):
message = String()
@login_required
def mutate(self, info):
return ProtectedMutation(message="Доступ відкрито лише для аутентифікованих користувачів.")
Тепер, якщо неаутентифікований користувач спробує виконати цю мутацію, він отримає повідомлення про помилку.
Управління доступом до даних
Тепер давай поговоримо про дозволи (permissions). Аутентифікація перевіряє, хто ти, а дозволи визначають, що тобі дозволено робити.
Django надає нам зручний механізм перевірки дозволів на рівні моделі. Наприклад, у моделі може бути дозвіл can_view, який дає право на перегляд даних.
Допустимо, у нас є модель Post:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
owner = models.ForeignKey('auth.User', on_delete=models.CASCADE)
class Meta:
permissions = [
("can_view", "Може переглядати пости"),
]
Тепер ми можемо додати перевірку дозволів у наші GraphQL запити:
from graphql_jwt.decorators import permission_required
class Query(ObjectType):
post_detail = Field(PostType, id=ID(required=True))
@permission_required('app_name.can_view')
def resolve_post_detail(self, info, id):
return Post.objects.get(id=id)
Цей запит буде доступний тільки користувачам із дозволом can_view. Якщо у користувача немає такого дозволу, він отримає помилку.
Кастомізація дозволів
Іноді вбудованих дозволів недостатньо, і нам потрібно написати свої. Наприклад, ми хочемо, щоб тільки власники поста могли його редагувати.
Приклад кастомного дозволу:
from graphql import GraphQLError
class PostOwnerPermission:
@staticmethod
def has_permission(info, post):
if info.context.user != post.owner:
raise GraphQLError("Ви не є власником цього поста.")
return True
Тепер використовуємо цей дозвіл у мутації:
class UpdatePost(Mutation):
class Arguments:
id = ID(required=True)
title = String()
content = String()
post = Field(PostType)
def mutate(self, info, id, title=None, content=None):
post = Post.objects.get(id=id)
PostOwnerPermission.has_permission(info, post)
if title:
post.title = title
if content:
post.content = content
post.save()
return UpdatePost(post=post)
Приклади налаштування дозволів на рівні схеми
Іноді простіше задати загальну політику безпеки для всієї схеми, ніж перевіряти доступ для кожного запиту чи мутації.
Щоб обмежити доступ до всієї GraphQL схеми, ми можемо використовувати middleware:
class OnlyAuthenticatedMiddleware:
def resolve(self, next, root, info, **args):
if not info.context.user.is_authenticated:
raise Exception("Будь ласка, увійдіть у систему, щоб скористатися GraphQL API.")
return next(root, info, **args)
GRAPHENE["MIDDLEWARE"] += [OnlyAuthenticatedMiddleware()]
Цей middleware перевіряє аутентифікацію для всіх запитів.
Приклади помилок та їх вирішення
Помилка "AnonymousUser is not authenticated": перевір, чи встановлено налаштування
MIDDLEWAREуsettings.py. Не забудь проGRAPHENE["MIDDLEWARE"]."Пропущено токен у заголовку запиту": переконайся, що ти передаєш токен у заголовку
Authorizationпід час виконання запитів."GraphQLError не обробляється": використовуй правильні класи помилок. Наприклад, для перевірки дозволів використовуй
GraphQLError, а не звичайнийException.
Тепер твій GraphQL API вміє перевіряти, хто звертається до даних, і віддає їх лише тим, хто має право їх бачити. Ти піднявся на рівень вище в мистецтві створення захищених систем!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ