9.9 KiB
Executable File
9.9 KiB
Executable File
🔧 Token Issue Fix - Восстановление подключений
Проблема
При восстановлении подключений после logout/login возникала ошибка 403 Forbidden при переключении между подключениями.
Причина
Middleware получал Guacamole токен напрямую из JWT payload, а не из активной сессии в Redis.
ДО исправления:
# middleware.py (строка 77)
user_token = jwt_payload.get("guac_token") # ❌ guac_token нет в JWT!
Проблема:
- JWT содержит только
session_id, а неguac_token - При логине создается новая сессия в Redis с новым Guacamole токеном
- Но middleware не загружал сессию из Redis, поэтому
user_tokenбылNoneили старый
Решение
✅ Исправление в middleware.py
Теперь middleware:
- Извлекает
session_idиз JWT - Загружает актуальную сессию из Redis
- Получает текущий Guacamole токен из сессии
ПОСЛЕ исправления:
# middleware.py (строки 77-112)
session_id = jwt_payload.get("session_id")
if session_id:
# Загружаем сессию из Redis
from auth.session_storage import session_storage
session_data = session_storage.get_session(session_id)
if session_data:
# ✅ Получаем актуальный Guacamole token из сессии
user_token = session_data.get("guac_token")
else:
# Сессия истекла или удалена
user_token = None
else:
# Backwards compatibility
user_token = jwt_payload.get("guac_token")
Как это работает
Схема аутентификации
┌─────────────────┐
│ 1. Пользователь │
│ логинится │
└────────┬────────┘
│
▼
┌────────────────────────────────────────────┐
│ 2. Guacamole возвращает auth_token │
└────────┬───────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 3. API создает Redis сессию: │
│ - session_id: "abc123" │
│ - guac_token: "guac_token_xyz" │
│ - user_info: {...} │
└────────┬───────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 4. API создает JWT token: │
│ { │
│ "username": "user", │
│ "role": "USER", │
│ "session_id": "abc123", ← ТОЛЬКО ID! │
│ "exp": ... │
│ } │
└────────┬───────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 5. Клиент отправляет запросы с JWT │
└────────┬───────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 6. Middleware: │
│ - Извлекает session_id из JWT │
│ - Загружает сессию из Redis ✅ │
│ - Получает актуальный guac_token ✅ │
└────────────────────────────────────────────┘
Восстановление подключений
User API Redis Guacamole
│ │ │ │
│─────LOGIN──────>│ │ │
│ │───AUTH───────────────────────────────>│
│ │<──guac_token_A────────────────────────│
│ │ │ │
│ │──CREATE SESSION──>│ │
│ │ (guac_token_A) │ │
│<─JWT(session_id)│ │ │
│ │ │ │
│──CREATE CONN───>│ │ │
│ │──GET TOKEN───────>│ │
│ │<─guac_token_A─────│ │
│ │────CREATE CONNECTION─────────────────>│
│<─connection_url─│ │ │
│ (token_A) │ │ │
│ │ │ │
│────LOGOUT──────>│ │ │
│ │──DELETE SESSION──>│ │
│ │ │ │
│─────LOGIN──────>│ │ │
│ │───AUTH───────────────────────────────>│
│ │<──guac_token_B────────────────────────│ ← NEW TOKEN!
│ │ │ │
│ │──CREATE SESSION──>│ │
│ │ (guac_token_B) │ │
│<─JWT(session_id)│ │ │
│ │ │ │
│──GET CONNECTIONS│ │ │
│ │──GET TOKEN───────>│ │
│ │<─guac_token_B─────│ ✅ CURRENT TOKEN │
│<─URLs (token_B) │ │ │
│ ✅ РАБОТАЕТ! │ │ │
Применение исправления
cd GuacamoleRemoteAccess
docker-compose restart api
Проверка
После применения исправления:
- ✅ Логинитесь в клиент
- ✅ Создайте подключение к любой машине
- ✅ Сделайте logout
- ✅ Залогиньтесь снова
- ✅ Восстановите подключение
- ✅ Создайте новое подключение к другой машине
- ✅ Переключайтесь между подключениями → 403 ошибки больше нет! 🎉
Технические детали
JWT Payload (после логина)
{
"username": "user",
"role": "USER",
"permissions": [],
"session_id": "4edb****************************8c45",
"token_type": "access",
"exp": 1730721881,
"iat": 1730718281,
"iss": "remote-access-api"
}
Замечание: guac_token НЕ хранится в JWT по соображениям безопасности.
Redis Session (при логине)
{
"user_info": {
"username": "user",
"role": "USER",
"permissions": []
},
"guac_token": "589f****************************6edc",
"ecdh_session_id": "abc123...",
"created_at": "2025-11-04T14:24:41.123456Z",
"expires_at": "2025-11-04T15:24:41.123456Z"
}
Backwards Compatibility
Исправление поддерживает старые JWT токены (если они содержат guac_token напрямую):
else:
# Старый формат JWT с guac_token напрямую (backwards compatibility)
user_token = jwt_payload.get("guac_token")
Это позволяет избежать проблем при rolling deployment.
Связанные файлы
GuacamoleRemoteAccess/api/auth/middleware.py- middleware для извлечения токенаGuacamoleRemoteAccess/api/auth/utils.py- создание JWT сsession_idGuacamoleRemoteAccess/api/auth/guacamole_auth.py- создание сессий в RedisGuacamoleRemoteAccess/api/auth/session_storage.py- хранилище сессийGuacamoleRemoteAccess/api/main.py- endpoint/connectionsдля восстановления
Дата исправления
2025-11-04