Добро пожаловать на одну из самых интересных и полезных лекций на нашем пути к созданию продвинутого и безопасного 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 умеет проверять, кто обращается к данным, и отдаёт их только тем, кто имеет право их видеть. Вы встали на уровень выше в искусстве создания защищённых систем!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ