Django Social Auth: Авторизация на Яндекс через OAuth2

4 января 2012

Понедельник, как говорится, начинается в субботу — праздники дали возможность немного поработать над своими проектами. Добавлен backend для авторизации на Яндекс через OAuth2. Особенности/ограничения:

  • Нельзя указывать права доступа в настройках приложения. Права доступа задаются для разных сервисов Яндекса при регистрации приложения. Там же прописывается redirect_uri.
  • В настройке YANDEX_OAUTH2_API_URL указывается URL того сервиса, из которого вы хотите получать информацию о пользователе. Проверено и работают 2 сервиса: Я.ru, url=’https://api-yaru.yandex.ru/me/’ и Мой Круг, url=’http://api.moikrug.ru/v1/my/’. Не получилось проверить Яндекс.Фотки (url=’http://api-fotki.yandex.ru/api/me/’), как я не пытался все время возникала 500 Internal Server Error. Возможно, в праздники идет какой-то апгрейт.

Буду благодарен за обратную связь по работе backend’a.

Обновление от 19.01
Служба поддержки Яндекса помогла разобраться с проблемой вызова API Фоток, за что я ей очень благодарен. Я переделал backend чтобы этот API можно было использовать в будущем, на сегодняшний день его использовать пока нельзя. Причина в том, что ответ от me не содержит id пользователя в системе (совсем) и login пользователя (неявно он есть в url альбомов), писать специально для Фоток частный случай обработки не очень хочется, надеюсь это исправится со временем.

Обновление 2
Код получения аватаров пользователей обновлен для поддержки Яндекса.

Ответы на: Django Social Auth: Авторизация на Яндекс через OAuth2

  • bashmish пишет:

    19 января, 2012

    Зашел сюда чтобы попросить 🙂 на Гитхабе написать не получается личное сообщение

    У omab был пофиксен достаточно серьезный баг ( https://github.com/omab/django-social-auth/pull/219 ), хочется чтобы он побыстрее попал в мастер твоего репозитария. Заранее спасибо 🙂

    PS: спасибо за новый бекенд и вообще за постоянную работу над проектом!

    • krvss пишет:

      19 января, 2012

      Сегодня будет, я раз в 2 недели делаю merge.

  • elmit пишет:

    16 февраля, 2012

    Привет. Очень нужна функциональность прерывания пайплайна, которая недавно появилась в «ванильной» версии django-social-auth. Можно ли как-то ускорить merge твоей версии?

    • krvss пишет:

      16 февраля, 2012

      Сегодня как раз день merge 🙂 Недавно сделал его.

  • elmit пишет:

    16 февраля, 2012

    Спасибо

  • elmit пишет:

    16 февраля, 2012

    Спасибо

  • softshape пишет:

    16 марта, 2012

    А есть ли где-то, кроме conceptor.ru, реализация клиентской части с всплывающими окнами? То, что сейчас лежит в examples, открывает сайт сервиса в этом же окне. Это категорически неправильно. На conceptor’е — правильно, но с использованием jQuery UI (функция dialog()) что м…. правильно, но не совсем.

    • krvss пишет:

      16 марта, 2012

      К сожалению пользователи редко делятся со мной своими проектами. Наверняка я знаю один, но тот не использует всплывающих окон. Интересующимся как сделать через окна обычно достаточно реализации conceptor’а.

      • softshape пишет:

        19 марта, 2012

        В conceptor’е очень много оформительского кода, завязанного на jQuery UI. Открыть новое окно само по себе несложно, это ровно одна функция window.open:

        $(document).ready(function() {
        $(‘.openid_list a’).click(function (e) {
        window.open($(this).attr(‘href’), ‘login’);
        return false;
        });
        });

        Но мне пока непонятно, как отследить момент завершения авторизации в этом окне.

        • krvss пишет:

          19 марта, 2012

          Про открытие окна я в курсе 🙂

          Момент завершения авторизации определяется так:

          1. Во всплывающем окне вызывается url, который обозначает успех авторизации
          2. В нем грузится специальный view со скриптом
          3. Скрипт через window.parent перегружает родительскую страницу

          Думал сделать поинтеллектуальнее — ну там можно типа вызвать какую-то умную функцию которая что-то там у родителя перерисует, но это потянуло в нашем случае прилично кода, а выигрыш был неочевиден. Остановились на простом reload.

          • softshape пишет:

            19 марта, 2012

            Прилично кода?

            window.opener.someSmartFunction(‘success’); window.close();

            Это все, что нужно. Мы, по крайней мере, так будем делать. Дело в том, что на основной странице в это время может быть, например, текст свежего комментария, который потеряется при тупом релоаде. Да, релоад можно сделать, но перед этим вызвать someSmartFunction(‘success’), чтобы она сделала какую-то подготовку страницы — форму с комментарием сабмитила, еще что-нибудь.

          • krvss пишет:

            19 марта, 2012

            Ну, как вы будете делать — это ваша боль 🙂 Непонятно, зачем ты меня спрашиваешь о том, что сам знаешь. И зачем рассказываешь мне то, что я сам знаю 🙂

  • softshape пишет:

    19 марта, 2012

    Чтобы сэкономить немного времени тем потомкам, что будут читать нашу переписку спустя какое-то время в попытках решить аналогичную задачу. Всем, кто меня слышит! Не смотрите на conceptor.ru, он вам не поможет! Вам нужен window.open() в начале и window.opener.myFunction() в конце. И все.

  • ur001 пишет:

    3 апреля, 2012

    Яндексу нужно обязательно указать redirect_uri, причём только один.
    Как тогда быть с 2-мя url-ами complete// и associate/complete//?

    • ur001 пишет:

      3 апреля, 2012

      Съелось парсером <backend>

  • krvss пишет:

    3 апреля, 2012

    да, проблема; думаю как решить.

    • ur001 пишет:

      4 апреля, 2012

      Эта проблема, кстати, актуальна и для других провайдеров. Но во большинстве случаев она решается. Например в Foursquare можно указать в качестве callback_uri только чать (например http://домен/soacial_auth/), и это работает для http://домен/soacial_auth/complete/foursquare/ и http://домен/soacial_auth/associate /complete/foursquare/

      Единственным верным решением я вижу создание единого callback_uri и дальнейшее разруливание действий на основе записи cookies, сессии и т.п.

      Кстати, помимо прочего есть сложность с привязкой пользователя по email. associate_by_email не может определить какое действие происходит — auth или associate. Получается я не могу привязать к существующему аккаунту провайдер, если уже зарегистрирован пользователь с совпадающим email-ом. Например я логинюсь под Яндексом-ом, забыв что этот аккаунт ещё не привязывал и содзаётся новый пользователь. Единственный способ перепривязать его — это отвязать Яндекс от нового аккаунта, залогиниться под старым и выполнить привязку. Но associate_by_email не даст этого сделать пока я не сменю email в аккаунте созанном через Яндекс.

      • krvss пишет:

        4 апреля, 2012

        Единственным верным решением я вижу создание единого callback_uri и дальнейшее разруливание действий на основе записи cookies, сессии и т.п.

        Да, я тоже не смог придумать другой вариант. Задание части uri было бы наилучшим вариантом, и тут Яндекс перегнул с безопасностью на мой взгляд. Вообще с ними можно попробовать пообщаться, там хорошая поддержка.

        Кстати, помимо прочего есть сложность с привязкой пользователя по email. associate_by_email не может определить какое действие происходит — auth или associate. Получается я не могу привязать к существующему аккаунту провайдер, если уже зарегистрирован пользователь с совпадающим email-ом. Например я логинюсь под Яндексом-ом, забыв что этот аккаунт ещё не привязывал и содзаётся новый пользователь. Единственный способ перепривязать его — это отвязать Яндекс от нового аккаунта, залогиниться под старым и выполнить привязку. Но associate_by_email не даст этого сделать пока я не сменю email в аккаунте созанном через Яндекс.

        Столкнулся тоже с этой проблемой — хуже всего, что для старой записи уже могут быть какие-то действия, и потом непонятно что с ней делать: мержить или оставить как была? Так как жалоб не поступало оставил существующую реализацию.

  • m0n61an пишет:

    24 сентября, 2012

    Столкнулся с проблемой при настройке Yandex OAuth. На Яндексе указываю Callback URI: http://***/auth/oauthcomplete/yandex-oauth2/
    При попытки логина по ссылке http://***/auth/oauthlogin/yandex-oauth2/ Яндекс выдает «Ошибка 400: redirect_uri_mismatch». Причиной является GET-параметр redirect_state. При его отсутствии ошибка исчезает.
    Для рабочей авторизации добавил параметр REDIRECT_STATE=False в класс YaruAuth: http://pastebin.com/HUSa6f1Y
    Подскажите, как избежать данной ошибки как-то более красиво и не править чужой код?

    • krvss пишет:

      25 сентября, 2012

      Посмотрел — дело не в REDIRECT_STATE, а в том, что он неправильно добавляется к URL.

      Вот как выглядит правильная ссылка:

      https://oauth.yandex.ru/authorize?state=g85M3M8ri5JdUJuAyFARY15PKAYw5ZAd&redirect_uri=http%3A%2F%2Fmyproj.ru%2Fcomplete%2Fyandex-oauth2%2F&redirect_state=Dg85M3M8ri5JdUJuAyFARY15PKAYw5ZAd&response_type=code&client_id=d782fbbb80af41ed869811b9af34ac2c

      А вот как генерируется сейчас:

      https://oauth.yandex.ru/authorize?state=GFX54CVNAuDiHkVVBnzGU38myi1OSPkt&redirect_uri=http%3A%2F%2Fmyproj.ru%2Fcomplete%2Fyandex-oauth2%2F%3Fredirect_state%3DGFX54CVNAuDiHkVVBnzGU38myi1OSPkt&response_type=code&client_id=d782fbbb80af41ed869811b9af34ac2c

      То есть во-первых, перед redirect_state стоит не «=» а «%3F», а во вторых после redirect_state стоит не «=» а «%3D». Соответственно, Яндекс приписывает redirect_state к redirect_uri и справедливо ругается на то, что redirect_uri совсем не тот, что должен.

      Вообще в коде добавление происходит через функцию url_add_parameters в модуле utils. Автор этой функции Матиас, так что я бы посоветовал написать ему issue вот тут: https://github.com/omab/django-social-auth/issues
      Либо сделать форк и поправить самому 🙂 Я поправить не успею — послезавтра в отпуск, дел невпроворот. Но с другой стороны это не наш баг 🙂

      • m0n61an пишет:

        1 октября, 2012

        Я все-таки настою на своём!

        Из social_auth/backends/__init__.py:686
        Store state in session for further request validation. The state value is passed as state parameter (as specified in OAuth2 spec), but also added to redirect_uri, that way we can still verify the request if the provider doesn’t implement the state parameter.

        Отсюда я делаю вывод, что ссылка создается правильно, так как redirect_state нам нужно передать далее в callback uri. И ошибка все-таки в реализации YaruAuth, так как там недостает параметра REDIRECT_STATE=False

        • krvss пишет:

          2 октября, 2012

          Я вижу, что правка уже в основной ветке. Ну, так тому и быть 🙂

          YaruAuth не мой бэкэнд, посмотрел еще по коду — понял, что в первый раз не заметил, что redirect_state передается внутрь redirect_uri для обратного вызова после авторизации, что меняет дело.

Comments closed