- portfolio/ 디렉토리를 personal/로 리네이밍 - lotto-backend의 Blog/Todo 라우트·CRUD를 personal 서비스로 이전 - lotto-backend에서 Blog/Todo 코드 제거 (DB 테이블 스키마는 유지) - nginx: /api/todos, /api/blog/ 라우팅을 personal로 추가 - docker-compose: portfolio → personal 서비스 변�� - deploy 스크립트: portfolio → personal 반영 데이터 마이그레이션은 배포 후 NAS에서 별도 수행 필요: 1. cp data/portfolio/portfolio.db data/personal/personal.db 2. sqlite3 data/lotto.db ".dump todos" | sqlite3 data/personal/personal.db 3. sqlite3 data/lotto.db ".dump blog_posts" | sqlite3 data/personal/personal.db Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
40 lines
1.2 KiB
Python
40 lines
1.2 KiB
Python
import os
|
|
import uuid
|
|
import time
|
|
import logging
|
|
from fastapi import Header, HTTPException
|
|
|
|
logger = logging.getLogger("portfolio")
|
|
|
|
EDIT_PASSWORD = os.getenv("PORTFOLIO_EDIT_PASSWORD", "")
|
|
TOKEN_TTL = 86400 # 24시간
|
|
|
|
_tokens: dict[str, float] = {} # token -> expiry timestamp
|
|
|
|
|
|
def authenticate(password: str) -> dict:
|
|
if not EDIT_PASSWORD:
|
|
raise HTTPException(status_code=503, detail="Edit password not configured")
|
|
if password != EDIT_PASSWORD:
|
|
raise HTTPException(status_code=401, detail="Invalid password")
|
|
token = uuid.uuid4().hex
|
|
_tokens[token] = time.time() + TOKEN_TTL
|
|
_cleanup()
|
|
return {"token": token, "expires_in": TOKEN_TTL}
|
|
|
|
|
|
def require_auth(authorization: str = Header("")):
|
|
token = authorization.replace("Bearer ", "").strip()
|
|
if not token or token not in _tokens:
|
|
raise HTTPException(status_code=401, detail="Authentication required")
|
|
if time.time() > _tokens[token]:
|
|
del _tokens[token]
|
|
raise HTTPException(status_code=401, detail="Token expired")
|
|
|
|
|
|
def _cleanup():
|
|
now = time.time()
|
|
expired = [t for t, exp in _tokens.items() if now > exp]
|
|
for t in expired:
|
|
del _tokens[t]
|