mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
2801-есть десктоп-версия. реализован ws для авторизации через тг-бота
This commit is contained in:
@@ -14,37 +14,79 @@ import (
|
||||
"rmser/internal/domain/account"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AuthMiddleware проверяет initData от Telegram
|
||||
func AuthMiddleware(accountRepo account.Repository, botToken string, maintenanceMode bool, devIDs []int64) gin.HandlerFunc {
|
||||
// Claims представляет JWT claims для токена авторизации
|
||||
type Claims struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TelegramID int64 `json:"telegram_id"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// AuthMiddleware проверяет JWT токен (Desktop) или initData от Telegram
|
||||
func AuthMiddleware(accountRepo account.Repository, botToken string, secretKey string, maintenanceMode bool, devIDs []int64) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 1. Извлекаем данные авторизации
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
var initData string
|
||||
var authData string
|
||||
|
||||
if strings.HasPrefix(authHeader, "Bearer ") {
|
||||
initData = strings.TrimPrefix(authHeader, "Bearer ")
|
||||
authData = strings.TrimPrefix(authHeader, "Bearer ")
|
||||
} else {
|
||||
// Оставляем лазейку для отладки ТОЛЬКО если это не production режим
|
||||
// В реальности лучше всегда требовать подпись
|
||||
initData = c.Query("_auth")
|
||||
authData = c.Query("_auth")
|
||||
}
|
||||
|
||||
if initData == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Авторизация отклонена: отсутствует подпись Telegram"})
|
||||
if authData == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Авторизация отклонена: отсутствует токен или подпись"})
|
||||
return
|
||||
}
|
||||
|
||||
// 2. Проверяем подпись (HMAC-SHA256)
|
||||
isValid, err := verifyTelegramInitData(initData, botToken)
|
||||
// 2. Попытка 1: Проверяем JWT токен (Desktop)
|
||||
token, err := jwt.ParseWithClaims(authData, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("неожиданный метод подписи: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(secretKey), nil
|
||||
})
|
||||
|
||||
if err == nil && token.Valid {
|
||||
// JWT токен валиден
|
||||
if claims, ok := token.Claims.(*Claims); ok {
|
||||
// Проверка режима обслуживания: если включен, разрешаем доступ только разработчикам
|
||||
if maintenanceMode {
|
||||
isDev := false
|
||||
for _, devID := range devIDs {
|
||||
if claims.TelegramID == devID {
|
||||
isDev = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isDev {
|
||||
c.AbortWithStatusJSON(503, gin.H{"error": "maintenance_mode", "message": "Сервис на обслуживании"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Set("userID", claims.UserID)
|
||||
c.Set("telegramID", claims.TelegramID)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Попытка 2: Проверяем Telegram InitData
|
||||
isValid, err := verifyTelegramInitData(authData, botToken)
|
||||
if !isValid || err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Критическая ошибка безопасности: поддельная подпись"})
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Критическая ошибка безопасности: недействительный токен или подпись"})
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Извлекаем User ID из проверенных данных
|
||||
values, _ := url.ParseQuery(initData)
|
||||
// Извлекаем User ID из проверенных данных
|
||||
values, _ := url.ParseQuery(authData)
|
||||
userJSON := values.Get("user")
|
||||
|
||||
// Извлекаем id вручную из JSON-подобной строки или через простой парсинг
|
||||
@@ -70,7 +112,7 @@ func AuthMiddleware(accountRepo account.Repository, botToken string, maintenance
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Ищем пользователя в БД
|
||||
// Ищем пользователя в БД
|
||||
user, err := accountRepo.GetUserByTelegramID(tgID)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Пользователь не зарегистрирован. Начните диалог с ботом."})
|
||||
|
||||
Reference in New Issue
Block a user