Авторизация через 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.
