GraphQL: как предотвратить очистку базы данных? - PullRequest
0 голосов
/ 20 октября 2018

Допустим, у меня есть конечная точка graphql на https://api.service.com/graphql, которая используется для создания официального пользовательского интерфейса компании на https://www.service.com + iOS-приложении + Android-приложении.Я хочу представить этот API-интерфейс общедоступным, чтобы сторонние приложения могли создавать поверх него запросы, запрашивая данные, однако я не хочу, чтобы они могли очищать всю мою базу данных.

Допустим,у нас есть тип:

type Thing {
  # public fields
  field1: String
  field2: String

  # fields only available in the official UI
  field3: String
  field4: String
}

и запрос:

{
  things(limit: Int!, offset: Int): [Thing]
}

Каков наилучший способ разрешить только официальный пользовательский интерфейс компании запрашивать все поля Thing иперебрать все вещи?Сторонним разработчикам следует разрешать запрашивать field1 и field2 только для каждой вещи и иметь некоторые ограничения относительно количества вещей, к которым они могут получить доступ.

Опция 1

Я думало необходимости, чтобы каждый клиент включал токен в каждый запрос запроса, чтобы официальный сайт, приложение iOS и приложения Android могли быть обнаружены и «включены в белый список».Однако что может помешать кому-то копаться в вашем комплекте javascript / app и находить указанный токен, если он хранится на клиенте?

Вариант 2

Я думал о публикации двух разных конечных точек API с двумяразличные схемы / наборы ограничений, например:

https://api.service.com/graphql - публично документировано и использует ограниченную схему.

https://api.service.com/graphql-anon - используется частным образом официальными пользовательскими интерфейсами и содержит полнофункциональный /неограниченная схема.

Но опять же, что помешает пользователю опросить пакет приложения и обнаружить, что существует конечная точка https://api.service.com/graphql-anon, и использовать ее вместо этого?

1 Ответ

0 голосов
/ 20 октября 2018

Во-первых, за исключением: я бы вообще рекомендовал иметь отдельную схему и конечную точку для вашего публичного API по любому ряду причин:

  • Очистить документацию. Совместное использование схемыозначает, что определенные поля или аргументы будут либо недоступны, либо будут выдавать ошибку, если они используются, и это может быть не так легко увидеть при взгляде на GraphiQL / GraphQL Playground или при анализе схемы.
  • Более чистый код. У ваших распознавателей не будет почти такой же логики ветвления, что облегчит их чтение и тестирование.
  • Различия под капотом. Возможна функциональность (например, кэширование илианалитика), которую вы реализуете для своего «внутреннего» API, который не имеет смысла для вашего общедоступного API (и может излишне увеличивать стоимость обслуживания конечной точки).
  • Ограничение скорости. Вы захотите внедрить какое-то ограничение скорости для вашего публичного API.Это, вероятно, будет проще сделать, если у вас есть отдельные конечные точки.

Тем не менее, очевидно, что поддержание двух отдельных API-интерфейсов сопряжено с определенными затратами, поэтому это не может быть подходящим решением во всех случаях.

Возвращаясь к рассматриваемому вопросу ... Независимо от вышеперечисленных соображений, как правило, вы используете аутентификацию на основе токенов для ограничения доступа ко всем или некоторым вашим API, но вы не будете хранить этот токен как часть вашегоприложение.Типичный базовый поток выглядит следующим образом:

  • Клиент вызывает некоторую конечную точку входа в систему с учетными данными пользователя и возвращает поток аутентификации
  • Токен временно сохраняется клиентом и отправляется скаждый последующий запрос к API
  • Когда пользователь выходит из системы, токен удаляется

Сервер использует токен для установления личности пользователя, и это можно сделатьдоступно для каждой функции распознавателя GraphQL через контекст запроса.Это позволяет эффективно возвращать данные только для определенного поля, если пользователь прошел проверку подлинности (или если его роль разрешает доступ к этому полю).Если поле недоступно для пользователя, оно может просто возвратить пустой или пустой массив, в зависимости от типа.

Конечно, вы также можете иметь небольшой набор запросов, доступных для неаутентифицированных пользователей.Этот подход позволяет вам иметь разные уровни доступа в зависимости от роли (таким образом, пользователь «администратор» может иметь доступ к большему количеству запросов или полей, чем «стандартный» пользователь, который имеет больше доступа, чем пользователь, не прошедший проверку подлинности).

В случае общедоступного API вы можете идентифицировать сторонние клиенты с помощью некоторой комбинации клиентских токенов аналогичным образом (возможно, им не нужно входить в систему, но используйте хэш токена и секрет, который вы назначаете им.на регистрацию например).Если у вас есть общая схема, можно поддерживать оба вида механизмов аутентификации.Таким образом, «сторонний клиент» может быть просто другой ролью, которая имеет доступ к некоторому подмножеству полей.

...