Приведи пример реализации базовой авторизации по логину и паролю с получением токена.

«Приведи пример реализации базовой авторизации по логину и паролю с получением токена.» — вопрос из категории Тестирование безопасности, который задают на 10% собеседований QA Тестировщик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Пример потока и кода для аутентификации пользователя с получением JWT-токена.

Типичный flow:

  1. Клиент отправляет POST-запрос с username и password на эндпоинт /auth/login.
  2. Сервер проверяет учетные данные (например, сравнивая хэш пароля с хранимым в БД).
  3. При успехе сервер генерирует и подписывает JWT-токен, содержащий payload (например, user_id, role).
  4. Сервер возвращает токен клиенту в теле ответа.
  5. Клиент сохраняет токен (например, в localStorage или памяти) и использует его в заголовке Authorization: Bearer <token> для последующих запросов.

Пример клиентского кода на Python (с использованием requests):

import requests
import json

# Конфигурация
AUTH_URL = "https://api.example.com/auth/login"
API_BASE_URL = "https://api.example.com/api"

class AuthClient:
    def __init__(self):
        self.token = None

    def login(self, username: str, password: str) -> bool:
        """Выполняет вход и сохраняет токен."""
        payload = {
            "username": username,
            "password": password
        }
        headers = {"Content-Type": "application/json"}

        try:
            response = requests.post(AUTH_URL, json=payload, headers=headers, timeout=5)
            response.raise_for_status()  # Выбросит исключение для статусов 4xx/5xx

            auth_data = response.json()
            self.token = auth_data.get("access_token")
            if self.token:
                print("Авторизация успешна.")
                return True
            else:
                print("Ошибка: токен не получен.")
                return False

        except requests.exceptions.RequestException as e:
            print(f"Ошибка сети или сервера: {e}")
            return False
        except json.JSONDecodeError:
            print("Ошибка: невалидный JSON в ответе сервера.")
            return False

    def make_authenticated_request(self, endpoint: str):
        """Выполняет авторизованный GET-запрос."""
        if not self.token:
            raise ValueError("Требуется авторизация. Сначала вызовите login().")

        url = f"{API_BASE_URL}/{endpoint}"
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json"
        }
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        return response.json()

# Использование
client = AuthClient()
if client.login("test_user", "StrongP@ssw0rd123"):
    user_data = client.make_authenticated_request("users/me")
    print(f"Данные пользователя: {user_data}")

Ключевые моменты безопасности и best practices:

  • Всегда используйте HTTPS для шифрования передаваемых учетных данных.
  • Храните пароли в хэшированном виде на сервере (используйте алгоритмы типа bcrypt, Argon2).
  • Токены должны иметь ограниченное время жизни (expiry).
  • Не храните чувствительные данные в JWT payload, так как он легко декодируется (но не подделывается).
  • Обрабатывайте ошибки (неверные данные, истекший токен, отказ сервера).