В этой лекции мы реализуем публичный API, обеспечивая его защиту от несанкционированного доступа и настраивая CORS для безопасной работы с фронтенд-приложением. Мы также обсудим, как обеспечить защиту через SSL и работать с безопасностью в реальном мире.
Требования к публичному API
Ваше API готовы использовать миллионы пользователей? Если мы говорим о публичном доступе, нужно подумать о нескольких ключевых аспектах:
- Доступность: API должно быть доступным для фронтенда, но не для злоумышленников.
- Защита данных: передача данных должна быть зашифрована.
- Контроль доступа: доступ к данным или сервисам API должен быть ограничен в зависимости от авторизации.
- Управление CORS: ваш API должен работать с определенными клиентами (например, React или Angular), но не быть открытым для всех.
Теперь, когда вы понимаете общую задачу, давайте погрузимся в реализацию.
Базовая настройка CORS и защита
Для начала настроим CORS и разрешим доступ только конкретному фронтенд-клиенту. Представьте, что у нас есть React-приложение, размещенное на домене https://myfrontend.com.
Шаг 1: Установка fastapi.middleware.cors
FastAPI делает настройку CORS простой благодаря встроенной поддержке. Если вы еще не устанавливали эту библиотеку, выполняем:
pip install fastapi[all]
Теперь готовимся к магии.
Шаг 2: Настройка CORS в FastAPI
Добавим в проект middleware для обработки CORS-запросов. Это позволит нам указать, какие источники запросов разрешены, какие методы можно использовать, а также какие дополнительные заголовки поддерживаются.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Настраиваем разрешенные источники
origins = [
"https://myfrontend.com", # Включаем ваш фронтенд-домен
]
# Добавляем CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"], # Разрешить конкретные методы
allow_headers=["*"], # Разрешить все заголовки
)
Вот и всё! Теперь ваш API готов работать только с запросами, исходящими с домена https://myfrontend.com. Любой другой источник будет отвергнут.
3. Защита эндпоинтов с помощью токенов
API без защиты — как дом без дверей: любой может войти. Поэтому мы добавим JWT-токены для управления доступом. Если вы не уверены, что такое JWT, подгляните в лекцию 33.
Шаг 1: Установка библиотек
Для работы с JWT нам понадобится библиотека pyjwt. Установите её:
pip install pyjwt
Шаг 2: Генерация токенов
Напишем небольшой пример, где пользователь получает токен после ввода логина и пароля. Используем для этого библиотеку jwt.
import jwt
from datetime import datetime, timedelta
SECRET_KEY = "mysecretkey" # Замените на собственный ключ
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=30) # Токен действует 30 минут
to_encode.update({"exp": expire})
token = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
return token
# Создаем токен для пользователя
token = create_access_token({"sub": "user_id"})
print("Ваш токен:", token)
Шаг 3: Проверка токенов
Теперь добавим защиту эндпоинтов, проверяя токены из заголовка запроса.
from fastapi import Depends, HTTPException, Header
from jose import jwt, JWTError
async def verify_token(authorization: str = Header(None)):
try:
payload = jwt.decode(authorization, SECRET_KEY, algorithms=["HS256"])
return payload # Возвращаем полезную информацию из токена
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/secure-data")
async def get_secure_data(payload: dict = Depends(verify_token)):
return {"message": "Welcome!", "user": payload["sub"]}
Теперь эндпоинт /secure-data доступен только тем, у кого есть корректный токен.
4. Настройка SSL (HTTPS)
Веб-приложение без HTTPS? Это как посылка с мороженым без холодильника: всё растает по дороге. Чтобы данные не были перехвачены злоумышленниками, настраиваем SSL.
Шаг 1: Создание самоподписанного сертификата
Для тестирования можно создать сертификат с помощью OpenSSL:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
Теперь у нас есть два файла: key.pem (приватный ключ) и cert.pem (сертификат).
Шаг 2: Настройка SSL в Uvicorn
Обновим команду запуска приложения:
uvicorn main:app --host 0.0.0.0 --port 443 --ssl-keyfile=key.pem --ssl-certfile=cert.pem
Ваше API теперь доступно по HTTPS. Сертификат самоподписанный, но для реальных проектов используйте сертификаты от авторитетных центров, таких как Let's Encrypt.
Полный пример защиты публичного API
Объединим всё: CORS, JWT-токены и SSL. Вот как будет выглядеть итоговый код:
from fastapi import FastAPI, Depends, HTTPException, Header
from fastapi.middleware.cors import CORSMiddleware
from jose import jwt, JWTError
from datetime import datetime, timedelta
app = FastAPI()
SECRET_KEY = "mysecretkey"
# Настраиваем CORS
origins = ["https://myfrontend.com"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST"],
allow_headers=["*"],
)
# Генерация и проверка токенов
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=30)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
async def verify_token(authorization: str = Header(None)):
try:
payload = jwt.decode(authorization, SECRET_KEY, algorithms=["HS256"])
return payload
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.post("/login")
async def login():
token = create_access_token({"sub": "user_id"})
return {"access_token": token}
@app.get("/secure-data")
async def secure_data(payload: dict = Depends(verify_token)):
return {"message": "Welcome back!", "user": payload["sub"]}
Этот код объединяет все аспекты безопасности. Добавьте SSL, чтобы завершить настройку, и ваш API готов к работе.
Теперь ваш API может безопасно взаимодействовать с фронтендом, обрабатывая кросс-доменные запросы, защищая данные через JWT и обеспечивая безопасность передачи данных с помощью SSL. Все клиенты, кроме тех, кому вы явно позволили доступ, останутся за бортом. Растите здоровый и надёжный API! 🚀
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ