🔐 Auth: інтеграція JWT в Memory Service + конфігурації

- Опціональна JWT auth в Memory Service endpoints
- get_current_service_optional для backward compatibility
- NATS auth config (nkeys) - шаблони
- Qdrant auth config (API keys) - шаблони
- Тестовий скрипт для повного потоку

TODO: Генерація реальних JWT/ключів та застосування конфігів
This commit is contained in:
Apple
2026-01-10 10:46:25 -08:00
parent 6c426bc274
commit 38cb96dd68
5 changed files with 193 additions and 5 deletions

View File

@@ -5,7 +5,7 @@ JWT Authentication для Memory Service
import os
import jwt
import time
from typing import Optional
from typing import Optional, Union
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from app.config import get_settings
@@ -42,8 +42,21 @@ def verify_jwt_token(token: str) -> dict:
raise HTTPException(status_code=401, detail="Invalid token")
async def get_current_service_optional(
credentials: Optional[HTTPAuthorizationCredentials] = Security(security, auto_error=False)
) -> Optional[dict]:
"""Dependency для отримання поточного сервісу з JWT (опціонально)"""
if not credentials:
return None
token = credentials.credentials
try:
payload = verify_jwt_token(token)
return payload
except HTTPException:
return None
async def get_current_service(credentials: HTTPAuthorizationCredentials = Security(security)) -> dict:
"""Dependency для отримання поточного сервісу з JWT"""
"""Dependency для отримання поточного сервісу з JWT (обов'язково)"""
token = credentials.credentials
payload = verify_jwt_token(token)
return payload

View File

@@ -8,6 +8,7 @@ DAARION Memory Service - FastAPI Application
"""
from contextlib import asynccontextmanager
from typing import List, Optional
from fastapi import Depends
from uuid import UUID
import structlog
from fastapi import FastAPI, HTTPException, Query
@@ -23,6 +24,7 @@ from .models import (
)
from .vector_store import vector_store
from .database import db
from .auth import get_current_service, get_current_service_optional
logger = structlog.get_logger()
settings = get_settings()
@@ -76,8 +78,12 @@ async def health():
# ============================================================================
@app.post("/threads", response_model=ThreadResponse)
async def create_thread(request: CreateThreadRequest):
async def create_thread(
request: CreateThreadRequest,
service: Optional[dict] = Depends(get_current_service_optional)
):
"""Create new conversation thread"""
# Auth опціональний: якщо JWT надано, перевіряємо; якщо ні - дозволяємо (dev режим)
thread = await db.create_thread(
org_id=request.org_id,
user_id=request.user_id,
@@ -123,7 +129,10 @@ async def list_threads(
# ============================================================================
@app.post("/events", response_model=EventResponse)
async def add_event(request: AddEventRequest):
async def add_event(
request: AddEventRequest,
service: Optional[dict] = Depends(get_current_service_optional)
):
"""Add event to conversation (message, tool call, etc.)"""
event = await db.add_event(
thread_id=request.thread_id,
@@ -158,7 +167,10 @@ async def get_events(
# ============================================================================
@app.post("/memories", response_model=MemoryResponse)
async def create_memory(request: CreateMemoryRequest):
async def create_memory(
request: CreateMemoryRequest,
service: Optional[dict] = Depends(get_current_service_optional)
):
"""Create long-term memory item"""
# Create in PostgreSQL
memory = await db.create_memory(