Facebook NoAuthorizationError после передачи signed_parameters вручную

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

КОНТЕКСТ

  • Вход на стороне сервера работает нормально
  • Вход на стороне клиента с использованием JS SDK отлично работает в Safari* (не тестировалось в Firefox, IE или мобильных устройствах, отличных от Chrome), но не в Chrome, о чем этот вопрос (и большинство мои пользователи используют Chrome, так что это очень важно)
  • Gem versions:
    • ruby (2.1.2)
    • рельсы (4.1.1)
    • аутентификация (0.4.7)
    • оаут2 (1.0.0)
    • омниаут (1.2.2)
    • omniauth-facebook (2.0.0)
    • omniauth-oauth2 (1.2.0)
  • Это для приложения в режиме разработки, где я, как разработчик, определенно авторизован для входа в систему.

* Под "работает нормально", я имею в виду, если вы просто скопировали код из RailsCast Райана Бейтса (http://railscasts.com/episodes/360-facebook-authentication?view=asciicast) работает без каких-либо дополнительных действий


TL:DR; Я передаю следующий URL, который должен работать...

`http://localhost:3000/auth/facebook/callback?signed_request=ASDF.JOUYOUY`
// Obviously signed_request is a much longer string

... но я все еще получаю сообщение об ошибке OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either acodeparameter or a signed request (viasigned_requestparameter or afbsr_XXXcookie)):


УСТРАНЕНИЕ НЕПОЛАДОК НА ДАННЫЙ МОМЕНТ + ОБЗОР МНОГИХ ОШИБОК/ ВОЗМОЖНЫХ РЕШЕНИЙ

Приведенные ниже кодовые решения основаны на коде из RailsCast Райана Бейтса:

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    window.location = '/auth/facebook/callback' if response.authResponse

Препятствие 1. Блокируются ли сторонние файлы cookie?

Не обязательно приводит к ошибке, просто делает так, что вы не можете подключить приложение к Facebook.

Для подключения вашего приложения к Facebook сначала необходимо войти в систему Facebook, потому что код FB.login (response) -> window.location = "/auth/facebook/callback" if response.authResponse зависит от правильности authResponse и содержащегося в нем параметра signedRequest.

Если файлы cookie заблокированы (например, Настройки Chrome > Дополнительные настройки > Конфиденциальность > Настройки содержимого > Блокировать сторонние файлы cookie отмечены ПРОВЕРКОЙ), вы никогда не получите объект authResponse обратно. Это комбинация вопроса и ответа здесь: /а>. Другими словами, если вы делаете FB.getLoginStatus, независимо от того, сколько раз вы нажимаете кнопку входа, статус всегда будет возвращаться как unknown согласно документам: https://developers.facebook.com/docs/ссылка/javascript/FB.getLoginStatus.

Код Решение на данный момент...: если FB.login возвращает ответ unknown, перенаправить обратно на вход на стороне сервера.

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      window.location = "/auth/facebook/callback"

Препятствие 2. Правильно ли передаются параметры?

Если у вас разблокированы сторонние файлы cookie, вы можете столкнуться с ошибкой:

OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a `code` parameter or a signed request (via `signed_request` parameter or a `fbsr_XXX` cookie)):

Несмотря на установку cookie: true в FB.init, иногда параметры все равно не передаются. Как указано в:

... вам может потребоваться вручную передать параметр signed_request. Быстрое наблюдение. Согласно документам Facebook (https://developers.facebook.com/docs/facebook-login/using-login-with-games), signedRequest должен состоять из двух компонентов, разделенных .. Не знаю как, но я уже получал один без .. Разделение важно, потому что вторая половина представляет собой закодированный base64url объект JSON, содержащий информацию code.

Код решения на данный момент...: вручную добавить параметр signed_request к URL-адресу обратного вызова.

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      window.location = ("/auth/facebook/callback?signed_request=" + response.authResponse.signedRequest)

Препятствие №3: по-прежнему ничего... все та же ошибка, что и №2

Может только я на данный момент?

Решение кода на данный момент...: проявите суперпедантичность, отделите code от signedRequest и добавьте к URL-адресу обратного вызова.

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      parsed_signed_Request = response.authResponse.signedRequest.split(".")
      key_info = base64_decode(parsed_signed_Request[1])
      // decoded via http://www.simplycalc.com/base64-source.php
      key_info_object = jQuery.parseJSON( key_info )
      window.location = ("/auth/facebook/callback?code=" + key_info_object["code"])

Препятствие № 4: CSRF обнаружен, но не по той причине, о которой вы подумали

Теперь я переехал прямо в кирпичную стену. Когда я запускаю код, как указано выше, я получаю обнаруженную ошибку CSRF. Есть несвязанная причина, по которой можно получить эту ошибку:

  • Вы можете получить эту ошибку, если ваше приложение Facebook находится в режиме разработки и вы пытаетесь войти в систему в режиме реального времени. В этом случае FB не позволяет разработчикам, не включенным в список, входить в систему. См. первый ответ на этот вопрос: Rails + omniauth + facebook - обнаружен csrf

Но проблема в моем случае была не в том, что выше, а в том, что параметр code был представлен без параметра state. Теперь были ответы, в которых говорилось, что вы можете исправить это, установив provider_ignores_state: true в файле конфигурации omniauth.rb, см. второй ответ на вопрос, указанный выше, НО это не исправление для меня. Почему? Потому что 1) мне не нравится отключать вещи, специально предназначенные для противодействия CSRF, и 2) кажется, что конфигурация срабатывает только для входа на стороне сервера. Добавление этого просто ничего не сделало для меня.

Это означает, что более серьезная проблема решения № 3 заключалась в том, что оно пыталось объединить подход к входу на стороне сервера (принимает параметры code и state) с подходом входа на стороне клиента (принимает параметр signed_request).

Это означает, что я вернулся к исходному вопросу... как передать signed_request, чтобы вход на стороне клиента работал?


Поскольку я уже много болтал об этом, позвольте мне указать на другую ошибку, которую я видел. У этого есть ответы, связанные с ошибками Facebook (Работа с ошибкой Oauth 2.0-facebook gem 100: этот код авторизации был использован), но помимо этого я нашел еще кое-что, что могло ее вызвать.

Как предлагается в этом руководстве (https://coderwall.com/p/bsfitw), вы match маршрут обратного вызова через get и post. Но когда я это делаю, мой logger показывает два запроса к Facebook, второй явно заблокирован и вызывает ошибку. (Также означает, что первый запрос прошел и пользователь уже авторизован/данные сохранены, что угодно). Мое решение состояло в том, чтобы установить маршрут так:

match 'auth/:provider/callback', to: 'signups#create_facebook', via: [:get]

person james    schedule 13.09.2014    source источник
comment
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что это эссе, включающее несколько правильных ответов, а не вопрос. Пожалуйста, разделите ответы на фактические ответы.   -  person Flimzy    schedule 02.06.2015
comment
Это единственная публикация на SO, которая точно отражает все несоответствия использования Omniauth на стороне клиента с Facebook SDK. Я согласен, что формат не соответствует SO, но спасибо за участие.   -  person Laurent    schedule 10.10.2015


Ответы (1)


Для тех, у кого еще есть эта проблема. Старайтесь не использовать «localhost: 3000» или что-то в этом роде. Измените /etc/hosts на новый URL-адрес, например

127.0.0.1 abc.com

Измените настройки приложения facebook на сайте developer.facebook.com, чтобы они указывали на новый URL-адрес (вместо использования localhost:3000 назовите его abc.com:3000).

и попробуйте снова войти в систему с помощью js facebook. Должно работать нормально!

person Marcos Santini    schedule 07.08.2017