Войти через Apple

@David, автор PR ответил на мой комментарий, каково ваше мнение по этому поводу?:

Я:

Этот PR, похоже, решает проблему с отсутствием имени и адреса электронной почты?

Автор PR:

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

Разве однократная передача при первоначальной авторизации не достаточна для нас?

Это лучше, чем ничего, но всё ещё не идеально. Например, если вы «войдёте через Apple», но затем нажмёте «Отмена» на экране «Создать учётную запись». Или если вы свяжете существующую учётную запись с Apple, а затем решите создать новую. Надеюсь, Apple исправит это до конца бета-тестирования :crossed_fingers:

5 лайков

Существует ли на данном этапе рабочая реализация функции «Вход через Apple»? Сайт, над которым я работаю (маркетплейс), планирует создать iOS-приложение, но без этой опции мы не сможем включить другие способы аутентификации, если не хотим, чтобы наше приложение было отклонено за нарушение правил App Store.

Насколько мне известно, нет. Мы ждем решения этой проблемы How to retrieve email and name? · Issue #8 · nhosoya/omniauth-apple · GitHub, хотя владелец репозитория безосновательно закрыл её.

Я не уверен, но разве такие коммиты, как этот и другие коммиты за август, не решают проблему?

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

Я являюсь большим сторонником этой функции. Мне бы очень хотелось, чтобы она была встроена в чистый Discourse, как и другие варианты входа.

Я думаю, что получение такой информации намеренно невозможно.

Размещение кнопки «Вход через Apple» в вашем приложении или на веб-сайте означает, что пользователи могут войти в систему или зарегистрироваться одним нажатием, используя уже имеющийся у них Apple ID, и избежать заполнения форм, проверки адресов электронной почты и выбора паролей. Вход через Apple предлагает новый, более конфиденциальный способ быстрого и простого входа в приложения и на веб-сайты, обеспечивая пользователям надежный единообразный опыт входа и удобство, заключающееся в отсутствии необходимости запоминать множество учетных записей и паролей. В случаях, когда вы решите запросить имя и адрес электронной почты, у пользователей будет возможность сохранить свой адрес электронной почты в тайне и вместо этого предоставить уникальный случайный адрес.

Посмотреть полную статью для разработчиков от Apple

Вы правы, конфиденциальность — одна из ключевых составляющих функции «Вход через Apple», но главное в вашей цитате — это:

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

Я не думаю, что автор этого модуля сможет это исправить — это изменение должно быть внесено со стороны Apple. Не вижу, чтобы это произошло в ближайшее время, поэтому, возможно, нам просто придётся попросить пользователей вручную вводить своё имя и адрес электронной почты в Discourse :cry:

4 лайка

Да, но что насчёт тех, кто в итоге решит не предоставлять свои данные?

Кстати, вот грубый концепт. :sweat_smile:

Хорошие новости:

Мне частично удалось заставить работать форк плагина Robert/merefield (форк включает только переход на копию гема omniauth, которую я собрал из последних исходников на GitHub). Однако на моём тестовом Discourse (где HTTPS работает сквозным шифрованием через ngrok) мне пришлось установить параметр «Site cookies» в настройках сайта в значение «(none)», чтобы аутентификация заработала. При отключённом параметре я могу создать учётную запись (даже если закрыл форму регистрации) и снова войти, но если параметр включён, это невозможно.

Ниже приведён трассировочный стек (backtrace) при неудачной попытке входа:

Трассировка ошибки при неудачном входе
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:112:in `report_to_store'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:103:in `add_with_opts'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:54:in `add'
/usr/local/lib/ruby/2.6.0/logger.rb:543:in `error'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:163:in `log'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:486:in `fail!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-oauth2-1.6.0/lib/omniauth/strategies/oauth2.rb:71:in `callback_phase'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:238:in `callback_call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:189:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/builder.rb:64:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:47:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/tempfile_reaper.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/conditional_get.rb:38:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:318:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/session/abstract/id.rb:259:in `context'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/session/abstract/id.rb:253:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/cookies.rb:648:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:101:in `run_callbacks'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/middleware/reporter.rb:43:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/rack/logger.rb:38:in `call_app'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:18:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/method_override.rb:22:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/executor.rb:14:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/sendfile.rb:111:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/host_authorization.rb:77:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.1.4/lib/mini_profiler/profiler.rb:184:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/message_bus-2.2.3/lib/message_bus/rack/middleware.rb:57:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:181:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/engine.rb:526:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/railtie.rb:190:in `public_send'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/railtie.rb:190:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:68:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:53:in `each'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:53:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:605:in `process_client'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:700:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:144:in `start'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'

Есть ли у кого-нибудь здесь предложения, как или можно ли переписать плагин так, чтобы для работы его основных функций больше не требовалось отключать эту настройку сайта? Код моего плагина находится по адресу https://github.com/sau226dev/discourse-sign-in-with-apple, а последний код, который я использовал для пересборки гема omniauth, должен быть в той же организации на GitHub.

Заранее спасибо за любую помощь,

sau226

4 лайка

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

Пока мы не получим позитивных новостей о том, что Apple устранила это фундаментальное препятствие (отправка имени и электронной почты при каждой попытке входа), поддерживать этот код, на мой взгляд, не имеет смысла. Не думаю, что есть способ обойти это? Именно поэтому я даже не пытался обновлять зависимости. В любом случае плагин не прошёл бы тестирование.

Таким образом, это не «релизный» плагин (иначе эта или подобная тема была бы в канале #plugin), и, скорее всего, он не получит никакой поддержки до тех пор, пока ситуация не изменится. Я с радостью «доведу его до ума», если эта проблема будет решена и Apple предоставит эту информацию.

Кстати, есть ещё одна существенная проблема: для использования плагина на собственном сайте необходимо оплатить участие в программе Apple Developer, чтобы получить доступ к настройкам в системах Apple. Боюсь, это отпугнёт многие сайты с ограниченным бюджетом, так как это не бесплатная или недорогая регистрация.

6 лайков

Мне кажется, @sau226 намекает на то, что отсутствие возвращаемого email/имени, по сути, не является блокирующим фактором?

@orenwolf Это (отсутствие возвращаемого email/имени при повторных входах) не казалось проблемой. Я считаю, что смог закрыть окно регистрации и возобновить её, передав правильные данные. Как я уже говорил, после этого я смог сразу войти через Apple без каких-либо проблем.

Единственная проблема, с которой я столкнулся, — ошибка CSRF, если не отключить настройку сайта, о которой я упоминал выше. Один из потенциальных недостатков — отсутствие поля имени в форме входа и то, что имя пользователя берётся как часть email до символа @ (однако, на мой взгляд, эти потенциальные проблемы либо не являются проблемами, либо пользователь может легко их исправить).

4 лайка

В дополнение к комментариям Дэвида выше, я нашел на сайте поддержки разработчиков Apple связанную тему, которая привлекла официальный ответ, подтверждающий проблему:

Официальный ответ:

Здравствуйте, aslkdjalksdjasdasd,
Поведение корректное: информация о пользователе передается в ASAuthorizationAppleIDCredential только при первой регистрации пользователя. При последующих входах в ваше приложение с помощью функции «Вход через Apple» с тем же аккаунтом никакая информация о пользователе не передается; в ASAuthorizationAppleIDCredential возвращается только идентификатор пользователя. Рекомендуется безопасно кэшировать первоначальный объект ASAuthorizationAppleIDCredential, содержащий информацию о пользователе, до тех пор, пока вы не подтвердите, что аккаунт успешно создан на вашем сервере.
Патрик

Как отмечает один из разработчиков:

Подождите… Если по какой-то причине первый перенаправляющий запрос от Apple теряется по одной из многих очень распространённых причин, мы навсегда теряем этого пользователя, поскольку другого способа получить его информацию нет. Действительно ли нет никакого другого способа получить эти данные?

и другой:

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

Поэтому я не думаю, что можно безопасно использовать это в продакшене, к сожалению. Это станет настоящим кошмаром для поддержки.

Я предлагаю отложить эту задачу до тех пор, пока Apple не осознает проблему, которую создала: в попытке повысить безопасность, похоже, они пожертвовали надёжностью в чрезмерной степени.

11 лайков

Это обидно. :cry:

1 лайк

Apple обновила страницу для разработчиков «Вход с помощью Apple», добавив больше информации о сборе данных, управлении данными и т. д.

5 лайков

Я создал запрос на слияние для обновления gem-пакета omniauth-apple до последней версии, которая включает этот коммит. Похоже, он может решить проблему с тем, что электронная почта пользователя не получалась при каждом входе.

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

  • Какой путь для URL-адреса перенаправления возврата требуется для настройки идентификатора сервиса в Apple?
  • Как получить «текстовый файл верификации» или это больше не требуется? При поиске я нашёл упоминания о том, что его можно скачать в Apple как часть настройки связи домена/электронной почты, но, похоже, это больше не актуально:
3 лайка

Спасибо.

Обычно вы отправляете PR после успешного тестирования :wink:

Пожалуйста, подтвердите, когда это будет сделано.

Кажется, что это очевидное решение, но меня бы больше убедило заявление от Apple о том, что они теперь отправляют email каждый раз. Обновление версии гема не решит проблему, если Apple не устранит её корень.

Я посмотрю на свою настройку, когда снова подпишусь на программу разработчика Apple, чего я ещё не сделал… (эта история немного демотивировала, честно говоря)

@David

Я попытался обновить наш форк плагина, чтобы использовать последнюю версию omniauth-apple. (Обратите внимание, что требуются некоторые другие изменения, а не просто обновление номера версии).

Кратко: всё ещё не работает.

Мне удалось с помощью хаков заставить это работать в моей песочнице, но всё ещё есть ряд проблем:

  1. Apple использует POST-запрос в колбэке. Это нехарактерно для реализаций OAuth, так как это означает, что куки с samesite=Lax не будут отправлены с запросом. Из-за этого Discourse не может прочитать куки сессии во время колбэка и выдает ошибку CSRF.

    НЕБЕЗОПАСНЫЙ обходной путь — отключить эту защиту, изменив настройки куки Discourse на samesite=None.

  2. Использование POST-запроса без CSRF-токена также активирует ещё одну меру безопасности в ядре.

    НЕБЕЗОПАСНЫЙ обходной путь — удалить эту строку.

  3. Я получал ошибку 403 от Apple, когда gem omniauth запрашивал JWK. Подозреваю, что заголовок Accept: устанавливается неправильно, но я это не подтвердил.

    НЕБЕЗОПАСНЫЙ обходной путь заключался в том, чтобы зашить ключи в код.

После всего этого мне наконец удалось войти через Apple. Вы можете попробовать это на https://sandbox.dtaylor.uk (я оставлю это работающим на несколько дней, но, пожалуйста, не вводите там ничего конфиденциального, так как это НЕБЕЗОПАСНО).

И затем… электронные адреса и имена всё ещё включаются только при первой аутентификации. Вы можете это проверить: войдите через Apple, отмените создание аккаунта, а затем попробуйте снова. При второй попытке ваши данные будут отсутствовать.

Итак, предполагая, что Apple не планирует что-то менять в ближайшее время… как мы можем заставить это работать?

Для пунктов (1) и (2) я думаю, мы могли бы преобразовать POST-запрос Apple в GET, не нарушая безопасность. Когда мы получаем POST на колбэке, мы рендерим JavaScript, который устанавливает window.location='/auth/apple/callback?code=...&state=...'. С этого момента всё будет работать так же, как и с любым другим провайдером. Однако, я думаю, перехват POST-запроса потребует некоторых изменений в API ядра.

Для пункта (3) я думаю, это, вероятно, можно исправить с помощью небольшой доработки в gem omniauth.

Но мы всё ещё застряли без имени и электронной почты, поэтому я не уверен, стоит ли исправлять эти другие проблемы :cry:

8 лайков

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