Архивирование ключей API и токенов доступа
У меня есть вопрос относительно того, как я должен обладать архитектурой REST API, используя ключи доступа и ключи API.
У меня есть API, который нуждается в аутентификации. Я хочу включить два варианта использования:
-
Пользователь регистрируется в интерфейсе с использованием OAuth2 (предоставление пароля) и получает токен доступа. Этот токен используется для аутентификации пользователя. Таким образом, пользовательский интерфейс, который сам использует API, может извлекать данные и отображать их.
-
Я также хочу, чтобы у пользователя был ключ API для выполнения одних и тех же вызовов, но в его приложении. Очевидно, что, вопреки токену доступа, я хочу, чтобы ключ API был долговечным. Кроме того, вопреки токена доступа, привязанного к данному пользователю (если мы вводим командный механизм, каждый пользователь будет иметь различный токен доступа, хотя они имеют доступ к тем же ресурсам), ключ API должен быть уникальным для проекта.
В то время как похоже, я не уверен, как это сделать. Я думаю, что внутри, как ключи API, так и токены доступа должны храниться в одной таблице, но ключи API не имеют времени истечения. Я прав?
Одна вещь, которую я не уверен, также является концепцией клиента. Похоже, что в спецификации клиент больше похож на внешнее приложение. Однако могу ли я использовать эту концепцию здесь?
Например, каждый "проект" на самом деле является другим клиентом (хотя клиент здесь - это одно и то же приложение, а не приложение, созданное сторонним разработчиком).
Следовательно, если пользователь A создает учетную запись в системе, клиент A будет автоматически создан с токеном доступа, привязанным к клиенту A, с долгоживущим токеном доступа (иначе ключом API). Это может быть использовано для выполнения вызовов API непосредственно на его код, например.
Затем, если пользователь A войдет в панель управления, будет создан временный токен доступа, но на этот раз без приложения, но привязанного к пользователю, с коротким сроком службы.
Звучит ли это здорово? Кто-нибудь уже реализовал такую вещь?
Спасибо!
Ответы
Ответ 1
Я думаю, вы не должны считать "ключи API" заменой токена доступа.
В любом случае вам придется использовать токен доступа, чтобы нести аутентификацию между запросами, поэтому то, что вы на самом деле моделируете с помощью ваших "ключей API", не является заменой обычного токена-носителя, а скорее другого клиента, который предоставляет другие типы грантов для запроса токена с.
Поток, который я лично реализую, следующий:
- Пользователь аутентифицируется с типом предоставления пароля с общим клиентом для каждого пользователя (т.е. клиент вашего веб-приложения, который является общедоступным, т.е. не имеет
client_secret
).
- Затем пользователь может создать свой собственный клиент. Согласно спецификациям OAuth2, они не являются общедоступными, поэтому они состоят из
client_id
и a client_secret
. Это то, что вы называете "API-ключами".
- Затем пользователь сможет запросить токен доступа через своего клиента с любым типом гранта, который вы хотите поддержать (например, прямые учетные данные клиента, код авторизации, неявные, третьи стороны и т.д.). Вам нужно будет немного рассказать о надлежащих методах обеспечения безопасности при работе с учетными данными клиента.
Очевидно, что вам нужно будет реализовать свой сервер OAuth2 таким образом, чтобы клиенты могли принадлежать определенным пользователям и имели разные приемлемые типы грантов (т.е. вы не можете разрешать использование разрешения пароля с помощью пользовательского клиента, в то время как вы можете хотите запретить любой тип гранта, отличный от пароля для вашего клиента веб-приложения).
Затем вы сможете определить токены TTL или их отсутствие в каждом клиенте или на основе типа гранта (например, токен доступа, запрошенный с помощью пароля, только для использования клиентом веб-приложения, будет иметь короткий TTL, тогда как авторизация код предоставит долгоживущие токены).
Однако я бы посоветовал полностью отказаться от ТТЛ и, скорее, использовать тип гранта refresh_token
для обновления токенов доступа с истекшим сроком действия.
Кроме того, вам, вероятно, придется определить систему авторизации какого-то определенного типа (ACL, RBAC, что угодно), чтобы определить, какой клиент может что-то сделать. Это означает, что каждый токен доступа должен содержать ссылку на клиент, используемый для его создания.
Итак, чтобы подвести итог, вот соотношения:
Пользователь имеет Клиент.
Клиент имеет Пользователь.
Клиент имеет много токенов.
Токен имеет Клиент.
Токен имеет Пользователь.
YMMV на двунаправленных направлениях.
Вы должны иметь возможность реализовать все, что я описал, с наиболее распространенными реализациями серверов OAuth2 любой платформы.
TL; DR: "Ключи API" на самом деле являются клиентами OAuth2 .
Ответ 2
Спасибо за ваш ответ.
На самом деле у меня действительно опыт работы с OAuth2, мой вопрос был более ориентирован на ключи API. Мне нравится идея ключа API, использующего токен доступа, но я думаю, что это не сработает. Ключ API исправлен и не изменяется, в то время как токен доступа может истекать.
Вопрос: как приложение может узнать, является ли это токеном доступа или ключами API. Я имею в виду, хорошо, скажем, что в моей базе данных каждый пользователь имеет столбец "api_key" в своей базе данных.
В отличие от токена доступа, api_key не истекает (хотя пользователь может в конечном итоге повернуть его). То, что я хочу, как я сказал, является однородной обработкой аутентификации.
Случай 1: мои собственные веб-приложения выполняют вызовы API
Работа выполняется следующим образом, используя OAuth2:
- Пользователь вводит свой пароль/пароль.
- Сервер авторизации возвращает токен доступа (например: "abc" ).
- В веб-приложении все вызовы API выполняются с использованием этого токена. Например: "/payments/1" с заголовком авторизации: "Bearer abc".
Приятный и простой.
Случай 2: у пользователя есть ключ API, который не истекает и может использоваться конфиденциально в собственном приложении
Очевидно, что механизм авторизации должен оставаться неизменным. Итак:
- Пользователь переходит в свой аккаунт и читает, что его ключ API "def".
- В своем серверном коде они могут выполнять один и тот же вызов с тем же механизмом аутентификации. Таким образом, он может называть "/payments/1" авторизацией: "Определение несущей".
И он должен работать. Как вы можете видеть, в обоих примерах ничего не изменилось. Они получают доступ к одному и тому же ресурсу, одному и тому же механизму авторизации... но в одном случае у нас есть токен доступа, а в другом случае у нас есть ключ API. И я понятия не имею, как я должен реализовывать это как с точки зрения базы данных, так и с помощью кода авторизации.
Одна потенциальная идея, которую я использовал, - это использовать другой механизм auth. Для OAuth это будет "Authorization: Bearer accessToken", тогда как для API это будет обычная проверка подлинности: "Авторизация: базовый apiKey".
Звучит ли это хорошо?
Ответ 3
Я написал сообщение о том, как использовать токены доступа для приложений RESTful: https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/. Возможно, это может дать некоторые намеки.
Чтобы ответить на ваши вопросы, я думаю, что нам нужно что-то однородное. Я имею в виду, что все ваши механизмы аутентификации должны основываться на токенах доступа. Ваши ключи API позволят вам получить токен доступа, который будет фактически использоваться для аутентификации.
Насколько я понимаю, у вас есть два типа пользователей ваших приложений:
- Конечные пользователи, использующие веб-интерфейс (логин с паролем через OAuth2)
- Приложения (вход с ключами API)
Итак, я бы реализовал эти два вида пользователей и сделал их доступными для токенов доступа. Агенты доступа будут использоваться в обоих случаях для доступа к службам RESTful.
Кроме того, я думаю, что этот ответ может дать вам несколько других советов: Защита моего REST API с помощью OAuth, но все же позволяющая аутентификацию через сторонних поставщиков OAuth (используя DotNetOpenAuth).
Надеюсь, он ответит на ваш вопрос.
Thierry