REST API для веб-сайта, который использует Facebook для аутентификации

86

У нас есть веб-сайт, на котором единственный способ войти в систему и пройти аутентификацию на сайте - это Facebook (это был не мой выбор). При первом входе в систему через Facebook для вас автоматически создается учетная запись.

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

Этот вопрос о том, как пройти аутентификацию на нашем веб-сайте из приложения / API, разбит на 2 части:

  1. Как правильно обрабатывать аутентификацию REST от API к веб-сайту, который использует только Facebook OAuth в качестве метода аутентификации?

Я много читал и исследовал стандартные методы аутентификации для REST API. Мы не можем использовать такие методы, как Basic Auth over HTTPS , поскольку учетных данных для пользователя как таковых нет. Что-то вроде этого, похоже, только для аутентификации приложений с помощью API.

В настоящее время, как я могу думать, лучший способ - вы попадаете в конечную точку / authorize в нашем API, он перенаправляет на Facebook OAuth, затем перенаправляет обратно на сайт и предоставляет «токен», который пользователь API может использовать для аутентификации последующих Запросы.

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

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

Мне кажется, что мне не хватает чего-то очень очевидного или я не совсем понимаю, как должны работать общедоступные REST API, поэтому любые советы и помощь будут очень благодарны.

Адам
источник
У меня есть аналогичный вопрос на stackoverflow.com/questions/30230482/…, в котором говорится о некоторых из них
JVK

Ответы:

99

ОБНОВЛЕНИЕ: см. Ниже

Я тоже много думал над этим вопросом. Мне это еще не совсем понятно, но вот маршрут, по которому я думаю идти. Я создаю REST API, и мои пользователи авторизуются только через Facebook.

О КЛИЕНТЕ:

  1. Используйте API Facebook для входа в систему и получения кода OAUTH2.
  2. Обменяйте этот код на токен доступа.
  3. При каждом вызове моего пользовательского API я буду включать идентификатор пользователя Facebook и токен доступа.

В API (для каждого метода, требующего аутентификации пользователя):

  1. Сделайте запрос к графику / me Facebook, используя токен доступа сверху.
  2. Убедитесь, что возвращенный идентификатор пользователя Facebook совпадает с идентификатором пользователя, переданным в мой API сверху.
  3. Если срок действия токена доступа истек, требуется дополнительная связь.

Мне еще предстоит это проверить. Как это звучит?

--- Обновление: 27 июля 2014 г., чтобы ответить на вопрос ---

Я использую вышеуказанный обмен только один раз при входе в систему. Как только я определяю, какой пользователь входит в систему, я создаю свой собственный токен доступа, и этот токен используется с этого момента в дальнейшем. Итак, новый поток выглядит так ...

О КЛИЕНТЕ:

  1. Используйте API Facebook для входа в систему и получения кода OAUTH2.
  2. Обменяйте этот код на токен доступа.
  3. Запросить токен доступа из моего API, включая токен Facebook в качестве параметра

Об API

  1. Получите запрос токена доступа.
  2. Сделайте запрос к графику / me Facebook, используя токен доступа facebook
  3. Убедитесь, что пользователь Facebook существует и соответствует пользователю в моей базе данных
  4. Создайте свой собственный токен доступа, сохраните его и верните клиенту для использования с этого момента
Крис Гринвуд
источник
Эй, это вроде запоздалый ответ, но ваше решение, похоже, решает проблему, которая возникла в моем первом ответе. Конечно, вам придется использовать HTTPS, чтобы не отправлять пару (id, token) по проводу в виде открытого текста. Но, похоже, должно работать!
Olivier Lance,
Я думаю, что хорошо позвонить / мне на сервер и сгенерировать собственный токен доступа, который будет использоваться мобильным клиентом.
Der_Meister
Я обнаружил, что хранить секреты FB в мобильном приложении - плохая практика. Facebook советует хранить его только на вашем сервере. developers.facebook.com/docs/opengraph/using-actions/…
Der_Meister
Если мы каждый раз отправляем user_id и access_token на сервер API (как параметры post / get). Создаст ли он дыру в безопасности, если кто-то сможет перехватить соединение?
Натан До
@NathanDo Используйте HTTPS между вашим клиентом и сервером API, и это не должно быть проблемой, если кто-то перехватит соединение (не говоря уже об уязвимостях типа Heartbleed).
dcr
15

Это моя реализация с использованием JWT (JSON Web Tokens), в основном похожая на обновленный ответ Криса. Я использовал Facebook JS SDK и JWT.

Вот моя реализация.

  1. Клиент: используйте Facebook JS SDK, чтобы войти в систему и получить токен доступа.

  2. Клиент: запросить JWT из моего API, вызвав /verify-access-tokenконечную точку.

  3. MyAPI: получает токен доступа, проверьте его, вызвав /meконечную точку Facebook API.

  4. MyAPI: если токен доступа действителен, находит пользователя из базы данных, регистрирует пользователя, если он существует. Создайте JWT с обязательными полями в качестве полезной нагрузки, установите срок действия, подпишите секретным ключом и отправьте обратно клиенту.

  5. Клиент: хранит JWT в локальном хранилище.

  6. Клиент: отправляет токен (JWT из шага 5) вместе с запросом на следующий вызов API.

  7. MyAPI: проверьте токен с секретным ключом, если токен действителен, замените токен на новый, отправьте его обратно клиенту вместе с ответом API. (Здесь после этого нет внешних вызовов API для проверки токена) [если токен недействителен / истек срок его действия, запросить повторную аутентификацию и повторение с 1]

  8. Клиент Заменяет сохраненный токен новым и использует его для следующего вызова API. Как только истечет срок действия токена, срок действия токена истечет, что приведет к отмене доступа к API.

Каждый токен используется один раз.

Прочитайте больше ответов о безопасности и JWT

Насколько безопасен JWT

Если вы можете декодировать JWT, насколько они защищены?

Веб-токены JSON (JWT) как токены идентификации пользователя и аутентификации

Все вайти
источник
3
Я думаю, что номер 3 должен быть лучше /debug_token, чтобы вы могли проверить, действительно ли токен предназначен для вашего приложения.
Peppe LG
2
Не запрашивать access_tokenв клиенте. Используйте «рабочий процесс кода». Прохожу codeв MyAPI и сделать еще один поездку туда и обратно на Facebook для обмена codeс access_token. Более подробно это объясняется здесь: developers.facebook.com/docs/facebook-login/security
omikron
5

Я пытаюсь ответить на тот же вопрос и в последнее время много читал ...

У меня не будет "ответа", но для меня все становится немного яснее. Вы читали комментарии к упомянутой вами статье ? Я нашел их действительно интересными и полезными.

В результате и в свете того, как все развивались с момента написания первой статьи, вот что, я думаю, я сделаю:

  • HTTPS везде - это позволяет забыть о HMAC, подписи, nonce, ...

  • Используйте OAuth2:

    • Когда запросы аутентификации поступают из моих собственных приложений / веб-сайта, используйте этот «трюк» (или его вариант), описанный в ответе на упомянутую ранее статью .

    • В моем случае у меня есть два типа пользователей: те, у кого есть классические учетные данные для входа и пароля, и те, кто зарегистрировался с помощью Facebook Connect.
      Поэтому я бы предоставил обычную форму входа с кнопкой «Войти через Facebook». Если пользователь входит в систему со своими «классическими» учетными данными, я бы просто отправил их на мою конечную точку OAuth2 с расширением grant_type=password.
      Если он решит войти через Facebook, я думаю, это будет двухэтапный процесс:

      • Сначала используйте Facebook iOS SDK, чтобы открыть сеанс FBSession.
      • Когда это будет сделано и приложению будет возвращено управление, должен быть способ получить идентификатор Facebook для этого пользователя. Я бы отправил только этот идентификатор на мою конечную точку OAuth2 с предоставлением расширения, которое мой сервер понимает как «использование идентификатора пользователя FB».

Обратите внимание, что я все еще интенсивно исследую все это, так что это может быть не идеальный ответ ... может быть, даже не правильный! Но я думаю, что это будет хорошей отправной точкой. Идея использования «расширенного гранта» для аутентификации Facebook может включать в себя его регистрацию для правильной работы? Я не совсем уверен.

В любом случае, я надеюсь, что смог хоть немного помочь вам, и что, по крайней мере, можно начать обсуждение, чтобы найти лучшее решение этой проблемы :)

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

А как насчет того, чтобы сделать это так:

  • Показать форму входа с кнопкой «Вход в Facebook»
  • Если выбран этот метод входа в систему, действуйте как SDK Facebook: откройте веб-страницу со своего сервера аутентификации, который инициирует вход в систему Facebook.
  • Как только пользователь вошел в систему, Facebook будет использовать ваш URL-адрес перенаправления для подтверждения; сделать так, чтобы этот URL-адрес указывал на другую конечную точку вашего сервера аутентификации (возможно, с дополнительным параметром, указывающим, что вызов поступил из приложения?)
  • При попадании в конечную точку аутентификации аутентификация может безопасно идентифицировать пользователя, сохранять его идентификатор пользователя FB / сеанс FB и возвращать токен доступа вашему приложению с использованием настраиваемой схемы URL, как это сделал бы SDK Facebook.

Выглядит лучше?

Оливье Ланс
источник
1
Спасибо за ваш ответ! Я думал о большей части того, что вы сказали, но основная проблема, которую я волновал при использовании FB iOS SDK и последующей отправке идентификатора пользователя Facebook, заключалась в том, что было бы легко отправить любой идентификатор, который вы хотите, на конечную точку API и заявить, что он другой пользователь? Вот где я обычно застреваю ..
Адам
На самом деле! Было глупо с моей стороны не думать об этом ... Значит, решение должно каким-то образом проходить через ваш собственный сервер аутентификации ...
Оливье Лэнс
Я обновил свой ответ другой идеей решения ... но только что понял, что вы упомянули об этом в своем исходном вопросе! Я больше ничего не вижу в данный момент ...
Оливье Ланс