Русский
  • SDK
  • OIDC

Реализация простого клиентского SDK OIDC

Logto предлагает разнообразные SDK для различных платформ. Помимо наших официальных SDK, мы призываем разработчиков из сообщества создавать свои собственные пользовательские SDK. В этой статье мы расскажем о создании базового клиентского SDK для OIDC.

Simeng
Simeng
Developer

Введение

Logto предоставляет нашим разработчикам и бизнес-группам комплексное решение по управлению идентификаторами клиентов и доступом (CIAM). Мы предоставляем широкий спектр готовых к использованию SDK для различных платформ и приложений. В сочетании с нашим облачным сервисом Logto вы можете легко установить высоко защищенный поток авторизации пользователя для вашего приложения в течение нескольких минут. Как компания, родившаяся из сообщества разработчиков, Logto ценит и поддерживает взаимодействие с нашим сообществом. Помимо официально разработанных SDK Logto, мы постоянно призываем и тепло приветствуем разработчиков из сообщества привнести свои знания, создавая более разнообразные и удобные для пользователя SDK, удовлетворяющие уникальным потребностям различных платформ и фреймворков. В этой статье мы кратко продемонстрируем, как шаг за шагом реализовать стандартный SDK auth OIDC.

Контекст

Протокол аутентификации OpenID Connect (OIDC) основан на фреймворке OAuth 2.0 и обеспечивает проверку идентификации и возможности однократного входа. Он позволяет пользователям аутентифицироваться в приложении и получать авторизацию для дальнейшего доступа к любым приватным ресурсам безопасно. За подробностями обратитесь к спецификации OIDC.

Рабочий процесс

Стандартный поток авторизации-код включает следующие шаги:

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

  1. Пользователь инициирует запрос на вход: Анонимный пользователь заходит в ваше приложение с публичной точки входа. Пытается аутентифицироваться и, возможно, дополнительно запросить доступ к защищенному ресурсу на стороннем приложении или сервисе.
  2. Аутентификация пользователя: Клиентское приложение генерирует URI аутентификации и отправляет запрос на сервер авторизации, который перенаправляет пользователя на свою страницу входа. Пользователь взаимодействует со страницей входа, используя широкий спектр методов входа и аутентифицируется на сервере авторизации.
  3. Обработка обратного вызова входа: После успешной аутентификации пользователь будет перенаправлен обратно в ваше приложение с выданным authorization_code. Этот authorization_code содержит все соответствующие разрешения, связанные со статусом аутентификации и запрошенными данными авторизации.
  4. Обмен токенами: Запрос на обмен токенами с использованием authorization_code, извлеченного из адреса перенаправления выше. В ответе:
    • id_token: Цифровой подписанный JWT, содержащий информацию об идентификаторе аутентифицированного пользователя.
    • access_token: прозрачный access_token, который можно использовать для доступа к конечной точке основной информации о пользователе.
    • refresh_token: Токен учетных данных, позволяющий пользователю поддерживать непрерывный обмен на access_token

Поток авторизации

  1. Доступ к информации о пользователе: Чтобы получить больше информации о пользователе, приложение может сделать дополнительные запросы к конечной точке UserInfo, используя прозрачный access_token, полученный в исходном потоке обмена токенами. Это позволяет получать дополнительные сведения о пользователе, такие как его электронный адрес или фотография профиля.
  2. Предоставление доступа к защищенному ресурсу: При необходимости приложение может сделать дополнительные запросы к конечной точке обмена токенами, используя refresh_token в сочетании с параметрами resource и scope, для получения специального access_token для доступа пользователя к целевому ресурсу. Этот процесс приводит к выдаче JWT в виде access_token, содержащего всю необходимую информацию об авторизации для доступа к защищенному ресурсу.

Реализация

Мы будем следовать некоторым стратегиям проектирования в нашем JavaScript SDK @logto/client для демонстрации процесса реализации простого SDK для вашего собственного клиентского приложения. Пожалуйста, учтите, что детальная структура кода может отличаться в зависимости от клиентского фреймворка, с которым вы работаете. Не стесняйтесь выбирать любой из официальных SDK Logto в качестве примера для вашего собственного проекта SDK.

Предварительный просмотр

Конструктор

Конструктор должен принимать logtoConfig в качестве входных данных. Это предоставляет все необходимые конфигурации, которые вам понадобятся для установки соединения auth через этот SDK.

В зависимости от платформы или фреймворка, которые вы используете для SDK, вы можете передать в конструктор экземпляр локального хранилища. Этот экземпляр хранилища будет использоваться для хранения всех токенов и секретов, связанных с авторизацией.

Инициализация аутентификации пользователя

Перед генерацией URL для запроса аутентификации необходимо выполнить несколько подготовительных шагов для обеспечения безопасного процесса.

Получение конфигураций OIDC от сервера авторизации

Определите приватный метод `getOidcConfigs' для извлечения конфигураций OIDC из конечной точки открытия сервера авторизации. Ответ на конфигурации OIDC содержит всю метаданные, которые клиент может использовать для взаимодействия с сервером авторизации, включая его местонахождение в конечных точках и возможности сервера. (Пожалуйста, обратитесь к OAuth OAuth Authorization Server Metadata Specs для более подробной информации.)

Генератор PKCE

Поток валидации PKCE(Proof Key for Code Exchange) является обязательным для всех общедоступных потоков обмена кодами авторизации клиентов. Он снижает риск перехвата атаки на код авторизации. Таким образом, `code_challenge и code_verifier необходимы для всех запросов авторизации общедоступных клиентских приложений (например, родное приложение и SPA).

Методы реализации могут варьироваться в зависимости от языков и фреймворков, которые вы используете. Пожалуйста, обратитесь к спецификации code_challenge и code_verifier для подробных определений.

Генерация параметра состояния

В потоке авторизации state parameter представляет собой случайно сгенерированное значение, которое включается в запрос авторизации, отправленный клиентом. Он служит мерой безопасности для предотвращения атак на подделку запросов межсайтового переадресации (CSRF).

Хранение промежуточной информации о сессии

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

Вход в систему

Все подготовленное выше, определить метод, генерирующий URL для входа пользователя и перенаправьте пользователя на сервер авторизации для аутентификации.

Обработка обратного вызова входа в систему

В предыдущем разделе мы создали метод sign-in, который генерирует URL для аутентификации пользователя. Этот URL содержит все необходимые параметры, необходимые для инициации потока аутентификации из клиентского приложения. Метод перенаправляет пользователя на страницу входа в систему сервера авторизации для аутентификации. После успешного входа в систему конечный пользователь будет перенаправлен обратно в указанное выше место redirect_uri. Все необходимые параметры будут перенесены в redirect_uri для выполнения следующего потока обмена токенами.

Извлечение и проверка URL обратного вызова

Этот шаг проверки чрезвычайно важен для предотвращения любых видов поддельных атак на обратный вызов авторизации. URL обратного вызова ДОЛЖЕН быть тщательно проверен перед отсылкой дальнейшего запроса обмена кода на сервер авторизации. Сначала нам нужно получить данные signInSession, которые мы сохранили в хранилище приложения.

Затем проверьте параметры обратного вызова URL до отправки запроса на обмен токенами.

  • Используйте ранее сохраненный redirectUri, чтобы проверить, совпадает ли callbackUri с тем, который мы отправили на сервер авторизации.
  • Использовать сохраненное ранее состояние state, чтобы проверить, совпадает ли возвращенное состояние со стороны, которое мы отправили на сервер авторизации.
  • Проверьте, нет ли ошибок, возвращаемых сервером авторизации
  • Проверьте наличие возвращенного authorization_code

Отправка запроса на обмен кодов

Как последний шаг потока аутентификации пользователя, мы будем использовать возвращенный authorization_code для отправки запроса на обмен токенами и получения необходимых токенов авторизации. Подробная информация о параметрах запроса приведена в спецификации обмена токенами.

  • код: authorization_code, полученный нами из callback URI
  • clientId: идентификатор приложения
  • redirectUri: такое же значение используется при генерации URL входа для пользователя.
  • codeVerifier: PKCE code verifier. Аналогично redirectUri, сервер авторизации будет сравнивать это значение с ранее отправленным, обеспечивая валидацию входящего запроса на обмен токенами.

Обработка обратного вызова входа

Все, что у нас есть. Давайте построим метод обработки обратного вызова signIn:

В результате запрос на обмен токенами вернет следующие токены:

  • id_token: OIDC idToken, JSON Web Token (JWT), который содержит информацию об аутентификации пользователя. id_token также может быть использован как Единый источник достоверности(SSOT) статуса аутентификации пользователя.
  • access_token: код авторизации по умолчанию, возвращаемый сервером авторизации. Может быть использован для вызова конечной точки информации о пользователе и получения информации об аутентифицированном пользователе.
  • refresh_token: (если в запросе авторизации присутствует scope offline_access): этот токен обновления позволяет клиентскому приложению получить новый access_token без необходимости повторной аутентификации пользователя, предоставляя доступ к ресурсам на более длительный срок.
  • expires_in: Продолжительность времени в секундах, в течение которой действителен access_token, до его истечения.

Проверка идентификационного токена

Проверка и извлечение утверждений из id_token - это важный шаг в процессе аутентификации для обеспечения подлинности и целостности токена. Вот ключевые шаги, которые участвуют в проверке idToken.

  • Проверка подписи: id_token цифрово подписан сервером авторизации с использованием его закрытого ключа. Клиентское приложение должно проверить подпись, используя открытый ключ сервера авторизации. Это гарантирует, что с токеном не было манипуляций и его действительно выдал настоящий сервер авторизации.
  • Проверка издателя: Проверьте, что "iss" (issuer) claim в id_token совпадает с ожидаемым значением, что указывает на то, что токен был выдан правильным сервером авторизации.
  • Проверка аудитории: Убедитесь, что claim "aud" (audience) в id_token совпадает с ID клиента приложения, что подтверждает что токен предназначен для клиентского приложения
  • Проверка срока действия: Проверьте, что claim "iat" (выдан в) в id_token не прошёл текущее время, что обеспечивает действительность токена. Поскольку есть расходы на сетевые транзакции, нам нужно установить терпимость времени выдачи при валидации claim iat полученного токена.

Возвращенный id_token - это стандартный JSON Web Token (JWT). В зависимости от используемого вами фреймворка, Вы можете найти различные удобные плагины для валидации JWT токена, которые помогут в декодировании и проверке токена. Для этого примера мы будем использовать jose в нашем JavaScript SDK для облегчения валидации и декодирования токена.

Получение информации о пользователе

После успешной аутентификации пользователя основная информация о пользователе может быть получена из OIDC id_token, выданного сервером авторизации. Однако из-за соображений производительности содержания токена JWT ограничено. Чтобы получить более подробную информацию о профиле пользователя, серверы авторизации, совместимые с OIDC, предлагают встроенную конечную точку информации о пользователе. Эта конечная точка позволяет получать дополнительные данные профиля пользователя, отправляя запросы на конкретные профили пользователей.

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

Получение токена доступа для авторизации защищенного ресурса

В большинстве случаев клиентскому приложению не только требуется аутентификация пользователя, но и необходимо получить авторизацию пользователя для доступа к определенным защищенным ресурсам или конечным точкам API. Здесь мы будем использовать refresh_token, полученный во время входа, для получения access_token(s), конкретно предоставленных для управления определенными ресурсами. Это позволяет нам получить доступ к этим защищенным API.

Итог

Мы предоставили важные реализации методов для процесса аутентификации и авторизации пользователя на стороне клиентского приложения. В зависимости от вашего конкретного сценария вы можете организовать и оптимизировать логику SDK соответствующим образом. Пожалуйста, обратите внимание, что могут быть вариации из-за различных платформ и фреймворков.

Для получении дополнительной информации изучите предложенные Logto SDK. Мы призываем больше пользователей присоединиться к разработке и принять участие в обсуждениях с нами. Ваш отзыв и вклад очень ценны для нас, поскольку мы продолжаем улучшать и расширять возможности SDK.

Приложение

Зарезервированные области

Logto зарезервировал области, которые вам нужно будет передать во время начального запроса на авторизацию. Эти области либо зарезервированы OIDC, либо Logto зарезервировал фундаментальные области для успешного процесса авторизации.

Название областиОписание
openidТребуется для предоставления id_token после успешной авторизации.
offline-accessТребуется для предоставления refresh_token, позволяющего вашему клиентскому приложению обновлять и продлевать access_token вне экрана.
profileТребуется для доступа к базовой информации пользователя

Конфигурация Logto

Имя свойстваТипОбязательноОписаниеЗначение по умолчанию
appIdстрокаtrueУникальный идентификатор приложения. Генерируется сервером авторизации для идентификации клиентского приложения.
appSecretстрокаСекрет приложения используется вместе с идентификатором приложения для проверки идентичности запросчика. Требуется для конфиденциальных клиентов, таких как веб-приложения Go или веб-приложения Next.js, и необязательно для общественных клиентов, таких как родные или одностраничные приложения (SPA)
endpointстрокаtrueВаш сервер авторизации root endpoint. Это свойство будет широко использоваться для генерации запросов на авторизацию.endpoint.
scopesсписок строкУказывает все необходимые области ресурсов, которые пользователь может попросить предоставить, чтобы получить доступ к любому определенному защищенному ресурсу.[reservedScopes]
resourcesсписок строкВсе индикаторы защищенных ресурсов, которые пользователь может запросить на доступ

Утилиты

generateRandomString