Авторизация через Telegram в Django и Python

Предисловие

В начале февраля Павел Дуров анонсировал, что у Telegram появился так называемый Telegram Login Widget. Проще говоря, теперь любой желающий может встроить авторизацию на своем сайте через Telegram, наряду с уже удобными способами входа через привычные для всех Google, Twitter, Facebook и так далее.

В этой заметке я хочу рассказать и наглядно показать как это сделать, используя Django. Исходный код свободно доступен в моем репозитории на GitHub. Пользуйтесь на здоровье.

Те, кто уже имеет опыт работы с Django Framework, знают, что он предоставляет готовую User модель для авторизации, более того, ее очень легко расширить или написать свою. Я решил пойти другим путём, дабы не городить своих велосипедов, воспользовался готовым и хорошо зарекомендовавшим себя пакетом для авторизации в различных сервисах — python-social-auth. Для тех, кто не в курсе, social-auth это набор готовых библиотек для авторизации через такие сайты как Twitter, Facebook, Instagram, Google, VK и многие других. Проект разбит на модули, где основным является social-core, там хранится набор т.н. бэкендов для авторизации. Помимо social-core, есть ряд пакетов для конкретных фреймворков. Для Django это social-app-django, для Tornado соответственно social-app-tornado и так далее. Покрыты практически все известные веб-фрейморки для Python. Так вот к чему это я?

Решил я внести свой вклад в развитие Open Source, и написал backend для авторизации через Telegram в основной модуль social-core. Готовый к слиянию Pull Request можно посмотреть здесь. Правда загвоздка в том, что автор проекта не спешит его сливать в master ветку, на сообщения не реагирует, поэтому пример кода будет базироваться на моем форке social-core. Будем надеяться, что PR примут. Вы можете внести свой вклад, оставив комментарий автору проекта в Issue, который я открыл по случаю готового PR.

Мой проект будет использовать Python 3.6 и Django 2.0.3. Если вам не нравится Django, то вы без труда можете использовать python-social-auth с любым другим фреймворком для реализации авторизации через Telegram для своего сайта.

Создание бота Telegram

Telegram Login Widget работает через бота, который предварительно нужно создать. Для его создания необходимо обратиться к Его Величеству @BotFather. Я уже писал статью про то как это сделать. Для нашего примера я создал бота с “привлекательным” названием @DjangoTelegramAuthBot. Кстати, после того как пользователь войдет на ваш сайт через свой Telegram аккаунт, у бота будет возможность инициировать диалог первым (при указании соответствующего разрешения).

Настройка параметров

После создания бота, необходимо сформировать js-скрипт для встраивания на сайт. А перед этим прописать будущий домен вашего сайта командой /setdomain в диалоге с @BotFather. Для удобного тестирования веб-приложения, предлагаю использовать утилиту ngrok. Поставить её можно через npm сразу в global:

npm install ngrok -g

Задача js-скрипта, сгенерированного на странице настроек, показать на сайте кнопку для входа. Вот такую:

Настройки можно задать на официальной странице Telegram. Они простые, разобраться нетрудно. Но обратите внимание на 2 параметра:

В Authorization Type необходимо выбрать способ авторизации пользователя:

  • Callback. Вызов произвольной JS функции после авторизации пользователя. Если выбрать этот параметр, то в скрипте виджета появится пример такой функции, вызывающий alert с именем, фамилией, псевдонимом и id.
  • Redirect to URL. Стандартный способ авторизации через редирект на заданный URL. Именно его в примере я и буду использовать. Сюда позже укажем URL через домен, полученный с помощью ngrok.

Создаем веб-приложение

Итак, склонируйте мой репозиторий. Для проекта желательно создать отдельное виртуальное окружения, чтобы не засорять системный Python и не хапнуть конфликтных ситуаций между зависимостями (а вдруг?). Установите все зависимости из requirements.txt.

Теперь необходимо рядом с settings.py создать .env файл из шаблона .env-template. Можно просто переименовать .env-template в .env. Переменной SOCIAL_AUTH_TELEGRAM_BOT_TOKEN присвойте токен вашего бота, полученный при создании в диалоге с @BotFather. SECRET_KEY в этом примере неважен, но при деплое на продакшен обязательно укажите сложный ключ.

Обратите внимание, что в моем проекте-шаблоне в качестве базы данных используется SQLite 3, это сделано для простоты первичной настройки и демонстрации. Следом выполните команду migrate:

python manage.py migrate

Это необходимо сделать для создания таблиц в базе данных для корректной работы приложения.

Теперь запускаем проект привычной командой:

python manage.py runserver

В отдельном окне терминала получим внешний адрес для сайта путем создания туннеля через утилиту ngrok.

ngrok http 8000

Как видно из скриншота моему приложению был присвоен домен e019b6e6.ngrok.io. Его необходимо прописать в настройках бота у всё того же @BotFather:

Теперь возвращаемся на страницу настройки виджета, где необходимо задать Redirect URL. Полный адрес будет выглядеть вот так:

e019b6e6.ngrok.io/auth/complete/telegram

Возникает вопрос, а как я получил такой путь? Дело в том, что путь /auth/ был задан в urls.py моего проекта для модуля urls.py пакета social_django:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('auth/', include('social_django.urls', namespace='social')),
    path('profile/', TemplateView.as_view(template_name='profile.html'), name='profile'),
    path('', TemplateView.as_view(template_name='login.html')),
]

А /complete/telegram это уже стандартный шаблон для редиректа после авторизации в бэкенд-сервисе.

# код social_django.urls
urlpatterns = [
    # authentication / association
    url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth,
        name='begin'),
    url(r'^complete/(?P<backend>[^/]+){0}$'.format(extra), views.complete,
        name='complete'),
    # disconnection
    url(r'^disconnect/(?P<backend>[^/]+){0}$'.format(extra), views.disconnect,
        name='disconnect'),
    url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>\d+){0}$'
        .format(extra), views.disconnect, name='disconnect_individual'),
]

Более подробно о пакете python-social-auth можно почитать в документации.

Теперь полученный на странице настроек виджета JS-код копируйте в шаблон login.html (вместо моего кода вставьте туда свой). После открывайте браузер и заходите на страницу e019b6e6.ngrok.io (помните, что ваш домен может отличаться).

Если вы всё сделали правильно, то увидите примерно вот такую картинку:

Смело кликайте на виджет, разрешите доступ на авторизацию, и при успешном входе вас перекинет на страницу profile

Поздравляю! Вы успешно авторизовались на сайте через Telegram. Теперь у вас есть время, чтобы разобраться как это работает, посмотрите код моего проекта. В основном необходимо взглянуть на settings.py, всю “грязную” работу за вас делают пакеты social-auth и social-app-django. Если вам интересно как работает процесс авторизации, то изучите мой Pull Request и официальный гайд от Telegram.