Пример Login button
Ссылка на документацию телеграм
Приложение разбито на две составляющие bot и web
Читая эту статью вы должны ознакомиться с основами питона, здесь не будут разобраны тривиальные вопросы, например импорты в файлах и DI. Также я полагаю что вы уже ознакомились с фреймворками aiogram и fastapi которые были использованы в этом туториале.
Подготовка перед запуском
После получения токена от бота вам нужно пойти в настройки этого бота, кнопка "Bot Settings" и перейти в раздел "Domain". В этом разделе нужно задать адрес на котором будет размещен веб сервис - тоесть то, куда будет переходить пользователь по нажатию на кнопку с login url
Разбор кода
Bot
@dp.message(commands={"login"})
async def cmd_login(message: Message) -> None:
login_markup = InlineKeyboardMarkup(**{
"inline_keyboard": [
[
InlineKeyboardButton(**{
"login_url": LoginUrl(**{
"url": f"{HOST_URL}/auth",
}),
"text": "login",
})
]
]
})
await message.answer("Here login button", reply_markup=login_markup)
Хендлер который реагирует на команду /login
, он отправляет простое сообщение с кнопкой которая переадресовывает пользователя на ваш сайт.
Собственно со стороны бота это весь нужный нам код.
Web
def check_user_data(data: TelegramAuthModel, token):
secret = hashlib.sha256()
secret.update(token.encode('utf-8'))
sorted_params = collections.OrderedDict(sorted(data.dict().items()))
msg = "\n".join(["{}={}".format(k, v)
for k, v in sorted_params.items() if k != 'hash'])
return data.hash == hmac.new(secret.digest(), msg.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
Функция которая проводит валидацию данных переданных от пользователя. Это нужно для того что-бы убедиться что данные пришли действительно от телеграма и юзер их не придумал сам. Алгоритм можно найти тут, а начальный код был взят отсюда JRootJunior правда там есть баг, оставляю найти его и другие различия для читателя.
async def login_route(request: Request, user: TelegramAuthModel = Depends()) -> Response:
if (ENVIRONMENT.lower().strip() == "production"):
if (not check_user_data(user, BOT_TOKEN)):
raise HTTPException(status_code=401, detail="Nice try hacker :D")
user_from_database = FakeRepo().get_user(user.id)
if (user_from_database["role_id"] == 2):
raise HTTPException(
status_code=401, detail="Sorry you don't have permission")
return templates.TemplateResponse("login.html", {
"request": request,
**user.dict()
})
Самый интересный кусок кода, это функция которая выступает обработчиком роута для логина пользователя. Именно она будет вызвана после "нажатия" пользователем кнопки login.
Здесь я валидирую данные, проверяю его роль и на основе этого возвращаю ответ.
Предполагается что FakeRepo
будет заменена на конкретную(другую) имплементацию общения с базой, здесь это выступает как пример алгоритма.
Config .env
ENVIRONMENT = getenv("env", "debug")
BOT_TOKEN = getenv("bot_token", "Aa:123")
HOST_URL = getenv("host_url", "")
Тривиально, задаём токен от бота и хост на котором будут запускаться сервисы. HOST_URL должен быть белым, тоесть доступным всем в интернете, адресом.
Как это запустить?
Бот работает в режиме long polling и ему не нужен белый айпи в отличие от веб сервиса.
Ручной запуск
Установка зависимостей
pip install -r requirements.txt
Bot, перед запуском проверьте переменные среды
python bot.py
Web построен на fastapi и для него нужен uvicorn, перед запуском проверьте переменные среды
uvicorn web:app --reload
Docker
Конфигурация написана в компоуз файле.
docker-compose up
Всё остальное произойдёт само.
Использование
После запуска веб сервисе перейдите на host_url
/docs - вы должны увидеть swagger документацию, пример ниже на скрине
Если вы видите такое же на своём экране то скорее всего всё отлично!
После этого вы должны зайти в бота и отправить ему команду /login
в ответ вы получите сообщение с кнопкой логина
После нажатия на эту кнопку вы будете перенаправлены на host_url
/auth и увидите данный экран
Здесь будет та информация о пользователе которую предоставил вам телеграм. Весь набор полей можно найти в специальной моделе
Итог
Здесь был реализован минимальный пример для работы с login button используя современные фреймворки aiogram v3 и fast-api Безусловно это решение не является единственно верным и правильним, жду ваших PR если у вас есть замечания и предложения.