209 lines
6.9 KiB
Markdown
209 lines
6.9 KiB
Markdown
# Telegram WebApp Authentication Guide
|
||
|
||
## 📋 Обзор
|
||
|
||
Система аутентификации использует Telegram WebApp initData для безопасной верификации пользователей.
|
||
|
||
## 🔧 Как это работает
|
||
|
||
1. **Frontend** получает `initData` от Telegram WebApp
|
||
2. **Backend** валидирует HMAC-SHA256 подпись
|
||
3. **Success**: Пользователь аутентифицирован, данные доступны в handlers
|
||
4. **Error**: Доступ запрещен (401 Unauthorized)
|
||
|
||
## 📝 Требования к переменным окружения
|
||
|
||
Добавьте в `.env` файл:
|
||
|
||
```env
|
||
BOT_TOKEN=ваш_токен_бота_от_@BotFather
|
||
```
|
||
|
||
## 🛡️ Middleware
|
||
|
||
### Auth Middleware
|
||
```go
|
||
// Применяется ко всем защищенным маршрутам
|
||
app.Use(middleware.AuthMiddleware(middleware.AuthConfig{
|
||
BotToken: cfg.BotToken,
|
||
}))
|
||
```
|
||
|
||
### Получение данных пользователя в handler
|
||
```go
|
||
userData := middleware.GetTelegramUser(c)
|
||
if userData == nil {
|
||
return c.Status(fiber.StatusUnauthorized).JSON(...)
|
||
}
|
||
|
||
// Используем userData.ID, userData.FirstName и т.д.
|
||
```
|
||
|
||
## 📡 API Эндпоинты
|
||
|
||
### POST /api/auth/validate
|
||
Валидация initData без middleware (для инициализации)
|
||
|
||
**Request:**
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/auth/validate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"initData": "query_id=AAHdF6IQAAAAAN0XohDhrOrc&user=%7B%22id%22%3AYOUR_TELEGRAM_USER_ID%2C%22first_name%22%3A%22YOUR_FIRST_NAME%22%2C%22last_name%22%3A%22YOUR_LAST_NAME%22%2C%22username%22%3A%22YOUR_USERNAME%22%2C%22language_code%22%3A%22en%22%2C%22is_premium%22%3Atrue%2C%22allows_write_to_pm%22%3Atrue%7D&auth_date=1634567890&hash=YOUR_HASH_HERE..."
|
||
}'
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Authentication successful",
|
||
"data": {
|
||
"id": YOUR_TELEGRAM_USER_ID,
|
||
"first_name": "John",
|
||
"last_name": "Doe",
|
||
"username": "johndoe",
|
||
"photo_url": "https://t.me/i/userpic/320/johndoe.jpg",
|
||
"auth_date": YOUR_AUTH_DATE,
|
||
"hash": "abcd1234..."
|
||
}
|
||
}
|
||
```
|
||
|
||
### GET /api/auth/me
|
||
Получение данных текущего аутентифицированного пользователя
|
||
|
||
**Request:**
|
||
```bash
|
||
curl -X GET http://localhost:8080/api/auth/me \
|
||
-H "X-Telegram-WebApp-Init-Data: ваш_init_data_здесь"
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "User data retrieved successfully",
|
||
"data": {
|
||
"id": YOUR_TELEGRAM_USER_ID,
|
||
"first_name": "John",
|
||
"last_name": "Doe",
|
||
"username": "johndoe",
|
||
"photo_url": "https://t.me/i/userpic/320/johndoe.jpg",
|
||
"auth_date": YOUR_AUTH_DATE,
|
||
"hash": "abcd1234..."
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🔒 Защищенные эндпоинты
|
||
|
||
Все следующие эндпоинты требуют аутентификации:
|
||
|
||
### User Routes
|
||
- `GET /api/me` - профиль пользователя
|
||
- `GET /api/user/transactions` - история транзакций
|
||
- `GET /api/user/purchases` - история покупок
|
||
|
||
### Quiz Routes
|
||
- `GET /api/quizzes` - список викторин
|
||
- `GET /api/quizzes/:id` - детали викторины
|
||
- `POST /api/quizzes/:id/submit` - отправка ответов
|
||
- `GET /api/quizzes/:id/can-repeat` - проверка возможности повтора
|
||
|
||
### Reward Routes
|
||
- `GET /api/rewards` - список призов
|
||
- `POST /api/rewards/:id/purchase` - покупка приза
|
||
|
||
### QR Routes
|
||
- `POST /api/qr/validate` - валидация QR кода
|
||
|
||
## 🔄 Как использовать в фронтенде
|
||
|
||
### 1. Получение initData из Telegram WebApp
|
||
```javascript
|
||
// В вашем Telegram Mini App
|
||
const initData = window.Telegram.WebApp.initData;
|
||
```
|
||
|
||
### 2. Отправка на бэкенд
|
||
```javascript
|
||
// Вариант 1: Через заголовок (рекомендуется)
|
||
const response = await fetch('/api/qr/validate', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-Telegram-WebApp-Init-Data': initData
|
||
},
|
||
body: JSON.stringify({ payload: 'qr_token_here' })
|
||
});
|
||
|
||
// Вариант 2: Через body для /api/auth/validate
|
||
const response = await fetch('/api/auth/validate', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({ initData })
|
||
});
|
||
```
|
||
|
||
### 3. Обработка ошибок
|
||
```javascript
|
||
if (!response.ok) {
|
||
if (response.status === 401) {
|
||
// Переадресация на страницу аутентификации
|
||
window.location.href = '/auth';
|
||
} else {
|
||
// Другая ошибка
|
||
console.error('Request failed:', response.statusText);
|
||
}
|
||
}
|
||
```
|
||
|
||
## ⚠️ Важные моменты
|
||
|
||
1. **Время жизни**: initData действителен 5 минут
|
||
2. **Безопасность**: Всегда проверяйте HMAC подпись на бэкенде
|
||
3. **Bot Token**: Храните в секрете, никогда в клиентском коде
|
||
4. **User ID**: Используйте `userData.ID` как уникальный идентификатор
|
||
|
||
## 🔧 Тестирование
|
||
|
||
### Генерация тестового initData
|
||
Используйте [Telegram WebApp Tools](https://telegram-web-app-tools.vercel.app/) для генерации тестовых initData.
|
||
|
||
### Пример curl с реальными данными
|
||
```bash
|
||
# Замените YOUR_INIT_DATA на реальные данные
|
||
curl -X POST http://localhost:8080/api/qr/validate \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Telegram-WebApp-Init-Data: YOUR_INIT_DATA" \
|
||
-d '{"payload": "test_qr_token"}'
|
||
```
|
||
|
||
## 🚀 Production Deployment
|
||
|
||
1. **HTTPS**: Обязательно используйте HTTPS в production
|
||
2. **Bot Token**: Используйте переменные окружения
|
||
3. **Rate Limiting**: Добавьте rate limiting для auth эндпоинтов
|
||
4. **Logging**: Логируйте неудачные попытки аутентификации
|
||
5. **Security**: Регулярно обновляйте зависимости
|
||
|
||
## 🔍 Отладка
|
||
|
||
### Распространенные ошибки
|
||
|
||
1. **401 Unauthorized**: Неверный initData или просрочен
|
||
2. **Hash verification failed**: Неверный bot token или поврежденные данные
|
||
3. **Missing Telegram init data**: Отсутствует заголовок или initData
|
||
4. **Auth data expired**: Данные старше 5 минут
|
||
|
||
### Debug режим
|
||
Для отладки можно временно отключить проверку времени:
|
||
```go
|
||
// В middleware/auth.go закомментируйте проверку времени
|
||
// if time.Since(authTime) > 5*time.Minute {
|
||
// return errors.New("auth data expired")
|
||
// }
|
||
``` |