• oauth
  • jwt
  • api
  • security
  • authentication
  • authorization
  • machine-to-machine

Защита ресурсов API для взаимодействия между машинами

Узнайте, как использовать OAuth 2.0 и JWT для защиты ваших ресурсов API для взаимодействия между машинами.

Gao
Gao
Founder

При создании проекта, который включает несколько сервисов, безопасность ресурсов API является критически важной задачей. В этой статье я покажу вам, как использовать OAuth 2.0 и JWT для защиты связи между сервисами (машина-к-машине), и как применять контроль доступа на основе ролей (RBAC), чтобы следовать принципу минимальных привилегий.

Начнем

Чтобы следовать, я предполагаю, что у вас есть следующие предварительные условия:

  • Аккаунт в Logto Cloud или самостоятеленая инстанция Logto
  • Как минимум два сервиса, которые должны взаимодействовать друг с другом

Для демонстрации давайте предположим, что у нас есть следующие сервисы:

  • Сервис корзины покупок, который предоставляет API для управления корзинами
    • Endpoint: https://cart.example.com/api
  • Сервис платежей, который предоставляет API для обработки платежей
    • Endpoint: https://payment.example.com/api

Процесс аутентификации

Теперь наш сервис корзины должен вызвать сервис платежей для обработки платежей. Процесс аутентификации следующий:

Некоторые ключевые понятия на диаграмме выше:

  • JWT (RFC 7519): JSON Web Token. См. нашу предыдущую статью для введения в JWT.
  • JWK (RFC 7517): JSON Web Key, который используется для проверки подписи JWT. Набор JWK - это набор JWKов.
  • Грант "client_credentials" (RFC 6749): тип гранта в OAuth 2.0. Он использует учетные данные клиента для получения токена доступа. Мы продемонстрируем детали в следующих разделах.

Каждый участник на диаграмме выше играет свою роль в процессе аутентификации:

  • Сервис корзины: клиент, которому нужно вызвать сервис платежей. Хотя это и сервис, он является клиентом в контексте OAuth 2.0, и такие клиенты мы называем "machine-to-machine applications" в Logto.
  • Logto: сервер авторизации OAuth 2.0, который выдает токены доступа.
  • Сервис платежей: ресурс API, который предоставляет API для обработки платежей.

Давайте пройдемся по процессу аутентификации шаг за шагом.

Первоначальная настройка

Чтобы выполнить процесс аутентификации, нам нужно создать приложение "machine-to-machine" (сервис корзины) и ресурс API (сервис платежей) в Logto.

Создание ресурса API

Поскольку наш сервис корзины должен знать о API сервиса платежей при выполнении аутентификации, сначала нужно создать ресурс API. Перейдите в Консоль Logto, нажмите API ресурсы в левом боковом меню и нажмите Создать ресурс API. В открывшемся диалоге мы предлагаем несколько руководств, чтобы помочь вам начать. Вы также можете нажать Продолжить без руководства, чтобы пропустить его.

Введите имя и идентификатор API, например, Сервис платежей и https://payment.example.com/api, затем нажмите Создать ресурс API.

После создания ресурса API вы будете перенаправлены на страницу с деталями. Мы можем оставить ее как есть на данный момент.

Создание приложения "machine-to-machine"

Нажмите Приложения в левом боковом меню и нажмите Создать приложение. В открывшемся диалоге найдите карточку Machine-to-machine и нажмите Начать создание.

Введите имя приложения, например, Сервис корзины, и нажмите Создать приложение. Будет показано интерактивное руководство, которое поможет вам настроить приложение. Вы можете следовать руководству, чтобы понять основные принципы использования, или нажать Готово и закончить, чтобы пропустить его.

Запрос токена доступа

Поскольку приложения "machine-to-machine" предполагаются защищенными (например, они развернуты в частной сети), мы можем использовать грант OAuth 2.0 "client_credentials" для получения токена доступа. Он использует основную аутентификацию для аутентификации клиента:

  • URL запроса - это конечная точка токена вашего экземпляра Logto. Вы можете найти и скопировать его на вкладке Дополнительные настройки на странице с деталями приложения "machine-to-machine".
  • Метод запроса - POST.
  • Заголовок запроса Content-Type - application/x-www-form-urlencoded.
  • Для заголовка Authorization значение - Basic <base64(app_id:app_secret)>, где app_id и app_secret - это ID и секрет приложения "machine-to-machine" соответственно. Вы найдете их на странице с деталями приложения.
  • Тело запроса должно указывать тип гранта и идентификатор API. Например, grant_type=client_credentials&resource=https://payment.example.com/api.
    • grant_type=client_credentials: фиксированное значение для гранта "client_credentials".
    • resource=https://payment.example.com/api: идентификатор API ресурса, к которому хочет получить доступ клиент.
    • Если приложению нужно получить разрешения с помощью областей (scopes), вы также можете указать области в теле запроса. Например, scope=read:payment write:payment. Мы обсудим области позже.

Вот пример запроса с использованием curl:

Успешный ответ будет выглядеть так:

Отправка запроса с заголовком авторизации

Теперь у нас есть токен доступа, и мы можем добавить его в заголовок Authorization запроса к ресурсу API. Например, если мы хотим вызвать API POST /payments службы платежей, мы можем отправить следующий запрос:

Проверка JWT

Вы можете заметить, что служба платежей должна проверять JWT с использованием набора JWK и может иметь локальный кэш набора JWK, чтобы избегать получения набора JWK с Logto каждый раз. К счастью, благодаря популярности JWT, существует множество библиотек, которые могут помочь вам достичь цели с помощью нескольких строк кода.

Эти библиотеки обычно называются "jose" (JavaScript Object Signing and Encryption) или "jsonwebtoken". Например, в Node.js мы можем использовать jose для проверки JWT:

Если проверка успешна, переменная payload будет декодированным полезным нагрузком JWT. В противном случае будет выброшена ошибка.

Применение контроля доступа на основе ролей

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

Предположим, что мы хотим разрешить сервису корзины создавать платежи, но не читать платежи.

Определение разрешений

В Logto "scopes" и "permissions" взаимозаменяемы. Перейдите на страницу с деталями ресурса API службы платежей и перейдите на вкладку Разрешения. Она должна быть пустой. Нажмите Создать разрешение, введите read:payment в качестве имени разрешения и введите Чтение платежей в качестве описания разрешения. Затем нажмите Создать разрешение.

Повторите вышеуказанные шаги, чтобы создать другое разрешение с именем write:payment и описанием Создание платежей.

Создание роли для "machine-to-machine"

Роль - это группа разрешений. В Logto приложения "machine-to-machine" могут быть назначены роли для предоставления разрешений. Нажмите "Роли" в левом боковом меню и нажмите Создать роль.

  1. Введите checkout в качестве имени роли и введите Служба оформления заказа в качестве описания роли.
  2. Нажмите Показать больше параметров. Выберите "Роль приложения machine-to-machine" в качестве типа роли.
  3. В разделе "Назначенные разрешения" нажмите на стрелку слева от названия ресурса API (Служба платежей) и выберите разрешение write:payment.
    Создать роль
  4. Нажмите Создать роль.
  5. Поскольку у нас уже есть приложение "machine-to-machine" (Сервис корзины), мы можем непосредственно назначить ему роль на следующем шаге. Установите флажок слева от имени приложения (Сервис корзины) и нажмите Назначить приложения.
Назначить роль приложению

Запрос токена доступа с областями

В дополнение к параметрам тела запроса, о которых мы говорили в Запрос токена доступа, мы также можем указать области в теле запроса. Например, если мы хотим запросить разрешение write:payment, мы можем отправить следующий запрос:

Чтобы запросить несколько областей, вы можете разделить их пробелами. Например, scope=write:payment read:payment.

Проверка областей

Если действие требует разрешения write:payment в службе платежей, мы можем проверить области, утверждая, что утверждение scope полезной нагрузки JWT:

Заключение

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

С Logto ваши API ресурсы защищены с помощью OAuth 2.0 и JWT, и вы можете следовать принципу минимальных привилегий, применяя контроль доступа на основе ролей. Кроме того, вы можете использовать Logto для управления вашими пользователями и их разрешениями, и даже интегрироваться с поставщиками идентификации третьих сторон.