feat: Добавлена новая система авторизации с JWT токенами

- Удален Basic Auth, заменен на современную JWT авторизацию
- Добавлена страница входа с красивым интерфейсом
- Обновлен фронтенд для работы с JWT токенами
- Добавлены новые зависимости: PyJWT, passlib[bcrypt], jinja2
- Создан тестовый скрипт для проверки авторизации
- Добавлено руководство по миграции
- Обновлена документация и README
- Улучшен дизайн поля ввода пароля на странице входа

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов
2025-08-17 18:29:06 +03:00
parent 3126ff4eb6
commit a979dd2838
10 changed files with 1238 additions and 98 deletions

199
test_auth.py Normal file
View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Тестовый скрипт для проверки новой системы авторизации LogBoard+
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
import requests
import json
import sys
from datetime import datetime
# Настройки
BASE_URL = "http://localhost:9001"
USERNAME = "admin"
PASSWORD = "admin123"
def test_login():
"""Тест входа в систему"""
print("🔐 Тестирование входа в систему...")
try:
response = requests.post(
f"{BASE_URL}/api/auth/login",
json={
"username": USERNAME,
"password": PASSWORD
},
headers={"Content-Type": "application/json"}
)
if response.status_code == 200:
data = response.json()
print(f"✅ Успешный вход! Получен токен: {data['access_token'][:20]}...")
return data['access_token']
else:
print(f"❌ Ошибка входа: {response.status_code} - {response.text}")
return None
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return None
def test_protected_endpoint(token):
"""Тест защищенного эндпоинта"""
print("\n🔒 Тестирование защищенного эндпоинта...")
try:
response = requests.get(
f"{BASE_URL}/api/auth/me",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 200:
data = response.json()
print(f"✅ Доступ к защищенному эндпоинту: {data}")
return True
else:
print(f"❌ Ошибка доступа: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return False
def test_projects_api(token):
"""Тест API проектов"""
print("\n📋 Тестирование API проектов...")
try:
response = requests.get(
f"{BASE_URL}/api/projects",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 200:
projects = response.json()
print(f"✅ Получен список проектов: {projects}")
return True
else:
print(f"❌ Ошибка получения проектов: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return False
def test_services_api(token):
"""Тест API сервисов"""
print("\n🐳 Тестирование API сервисов...")
try:
response = requests.get(
f"{BASE_URL}/api/services",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 200:
services = response.json()
print(f"✅ Получен список сервисов: {len(services)} контейнеров")
return True
else:
print(f"❌ Ошибка получения сервисов: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return False
def test_logout(token):
"""Тест выхода из системы"""
print("\n🚪 Тестирование выхода из системы...")
try:
response = requests.post(
f"{BASE_URL}/api/auth/logout",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 200:
print("✅ Успешный выход из системы")
return True
else:
print(f"❌ Ошибка выхода: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return False
def test_unauthorized_access():
"""Тест доступа без авторизации"""
print("\n🚫 Тестирование доступа без авторизации...")
try:
response = requests.get(f"{BASE_URL}/api/projects")
if response.status_code == 401:
print("✅ Правильно отклонен доступ без авторизации")
return True
else:
print(f"❌ Неожиданный ответ: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"❌ Ошибка соединения: {e}")
return False
def main():
"""Основная функция тестирования"""
print("🧪 Тестирование новой системы авторизации LogBoard+")
print("=" * 60)
print(f"📅 Время тестирования: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"🌐 URL: {BASE_URL}")
print(f"👤 Пользователь: {USERNAME}")
print("=" * 60)
# Проверяем доступность сервера
try:
response = requests.get(f"{BASE_URL}/healthz")
if response.status_code != 200:
print("❌ Сервер недоступен")
sys.exit(1)
print("✅ Сервер доступен")
except Exception as e:
print(f"❌ Сервер недоступен: {e}")
sys.exit(1)
# Тестируем вход
token = test_login()
if not token:
print("❌ Тест провален: не удалось войти в систему")
sys.exit(1)
# Тестируем защищенные эндпоинты
success = True
success &= test_protected_endpoint(token)
success &= test_projects_api(token)
success &= test_services_api(token)
# Тестируем выход
success &= test_logout(token)
# Тестируем доступ без авторизации
success &= test_unauthorized_access()
print("\n" + "=" * 60)
if success:
print("🎉 Все тесты пройдены успешно!")
print("✅ Новая система авторизации работает корректно")
else:
print("❌ Некоторые тесты провалились")
print("🔧 Проверьте настройки и логи сервера")
print("=" * 60)
if __name__ == "__main__":
main()