JavaRush /Курсы /Модуль 4: FastAPI /Защита API с использованием токенов безопасности

Защита API с использованием токенов безопасности

Модуль 4: FastAPI
21 уровень , 7 лекция
Открыта

Давайте представим ваш API как дверь в ваш дом. Если дверь всегда открыта и любой может войти, то это довольно-таки рискованная ситуация. В контексте API это грозит тем, что злоумышленники смогут получить доступ к данным вашего приложения или вызвать нежелательные изменения.

Токены безопасности — это ключи, которые предоставляются пользователям (или системам) для того, чтобы предоставить доступ к данным и сервисам API. Защитить API с использованием токенов — значит запереть дверь и выдавать ключи только тем, кто действительно имеет право войти.

Задачи токенов безопасности:

  1. Убедиться, что запрос исходит от авторизованного пользователя.
  2. Определить, какие действия пользователь может выполнять.
  3. Защитить ваши эндпоинты от несанкционированного доступа.

Введение в токены безопасности: JWT

Самым популярным вариантом для работы с токенами в современных API является JSON Web Token (JWT). Это стандарт RFC 7519, который позволяет безопасно передавать информацию между сторонами в виде JSON-объекта.

JWT — это не просто строка, а структурированный объект, который состоит из трех частей:

  1. Header (заголовок) — содержит информацию о типе токена и алгоритме шифрования.
  2. Payload (полезная нагрузка) — содержит данные, которые мы хотим передать (например, идентификатор пользователя).
  3. Signature (подпись) — используется для проверки того, что токен не был подделан.

Когда объединены эти три части, они образуют строку, которая выглядит примерно вот так:


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjM0NTY3ODkwLCJleHAiOjE2ODg4OTk5OTl9.KyJw2aKXgWU1Lp5Jd0xWJoN3sUYOZ0qGqH8GDF8JMoQ

Установка необходимых библиотек

Для работы с токенами безопасности в FastAPI потребуется библиотека python-jose для генерации и проверки JWT. Также понадобится python-multipart для чтения данных формы (используется при аутентификации).

Установим их командой:


pip install python-jose python-multipart

Настройка безопасности в FastAPI

  1. Создание модели пользователя

    Мы начнем с модели данных для пользователя. Эту модель мы будем использовать для хранения информации о пользователях, прошедших аутентификацию.

    
    from pydantic import BaseModel
    
    class User(BaseModel):
        username: str
        full_name: str | None = None
        email: str | None = None
        disabled: bool | None = None
    

    Теперь создадим ещё одну модель для передачи данных при входе пользователя:

    
    class UserInDB(User):
        hashed_password: str
    

    Обратите внимание на поле hashed_password. Мы не храним пароли в открытом виде. Хранение "хэшированных" паролей — это безопасная практика.

  2. Настройка базы данных пользователей

    Для упрощения мы пока создадим базу данных пользователей в памяти:

    
    db_users = {
        "jsmith": {
            "username": "jsmith",
            "full_name": "John Smith",
            "email": "jsmith@example.com",
            "hashed_password": "fakehashedpassword",
            "disabled": False,
        }
    }
    
    def get_user(db, username: str):
        user = db.get(username)
        if user:
            return UserInDB(**user)
    
  3. Создание функций для работы с токенами

    Для создания JWT используем библиотеку jose.

    
    from jose import JWTError, jwt
    from datetime import datetime, timedelta
    
    SECRET_KEY = "secret"  # Используйте более надёжный ключ в реальных проектах
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30
    
    def create_access_token(data: dict):
        to_encode = data.copy()
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        to_encode.update({"exp": expire})
        encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
        return encoded_jwt
    

    Для проверки токенов декодируем JWT и извлекаем данные.

    
    def verify_token(token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            username: str = payload.get("sub")
            if username is None:
                raise ValueError("Invalid token")
            return username
        except JWTError:
            raise ValueError("Invalid token")
    
  4. Реализация аутентификации

    Теперь создадим эндпоинт, на котором пользователь сможет аутентифицироваться и получить токен.

    
    from fastapi import Depends, FastAPI, HTTPException, status
    from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
    
    app = FastAPI()
    
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
    
    def authenticate_user(username: str, password: str):
        user = get_user(db_users, username)
        if not user or user.hashed_password != "fakehashedpassword":  # Используйте bcrypt в реальных проектах
            return False
        return user
    
    @app.post("/token")
    async def login(form_data: OAuth2PasswordRequestForm = Depends()):
        user = authenticate_user(form_data.username, form_data.password)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect username or password",
                headers={"WWW-Authenticate": "Bearer"},
            )
        access_token = create_access_token(data={"sub": user.username})
        return {"access_token": access_token, "token_type": "bearer"}
    
  5. Защита эндпоинтов с использованием токенов

    Теперь мы можем добавить защиту на эндпоинт, чтобы требовалось отправлять токен для доступа.

    
    from fastapi import Depends
    
    async def get_current_user(token: str = Depends(oauth2_scheme)):
        try:
            username = verify_token(token)
            user = get_user(db_users, username)
            if user is None:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="Could not validate credentials",
                    headers={"WWW-Authenticate": "Bearer"},
                )
            return user
        except ValueError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid token",
                headers={"WWW-Authenticate": "Bearer"},
            )
    
    @app.get("/users/me")
    async def read_users_me(current_user: User = Depends(get_current_user)):
        return current_user
    

Полезные советы и практическое применение

Токены безопасности используются повсеместно. Например:

  • В e-commerce платформах для защиты личного кабинета.
  • В корпоративных приложениях для разграничения прав доступа.
  • В микросервисной архитектуре для авторизации между сервисами.

Учтите, что:

  1. Никогда не используйте простой текстовый пароль. Используйте библиотеки вроде bcrypt или argon2 для хэширования.
  2. Токены имеют срок действия. Обновляйте их с помощью рефреш-токенов.
  3. Не передавайте токены через незащищённые соединения (используйте HTTPS).

Теперь у нас есть базовая настройка безопасности FastAPI с токенами. Мы сделали первый шаг к тому, чтобы не только создавать, но и защищать наши API.

1
Задача
Модуль 4: FastAPI, 21 уровень, 7 лекция
Недоступна
Простая защита эндпоинта
Простая защита эндпоинта
1
Задача
Модуль 4: FastAPI, 21 уровень, 7 лекция
Недоступна
Защита эндпоинта с JWT
Защита эндпоинта с JWT
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ