feat(portfolio): 백엔드 서비스 + 인프라 설정
- FastAPI 앱: DB(5테이블), Pydantic 모델, 토큰 인증, 전체 API 라우트 - Docker Compose: portfolio 서비스 (포트 18850) - Nginx: /api/profile/ → portfolio:8000 - 배포 스크립트: portfolio 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
portfolio/app/auth.py
Normal file
39
portfolio/app/auth.py
Normal file
@@ -0,0 +1,39 @@
|
||||
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]
|
||||
Reference in New Issue
Block a user