Files
dbx-orderlist/app/main.py
T
king 88d7b1ba7a feat(sso): SESSION_SECRET_KEY 미설정 시 fail-fast
- SESSION_SECRET_KEY 가 .env 에 없으면 컨테이너 기동 단계에서 RuntimeError.
  알려진 기본값(super-secret-key) 폴백 제거로 양쪽 secret 불일치 사고 방지.
- .env.example 의 SESSION_SECRET_KEY 안내 강화 (openssl 명령, dbx-main 동기화 언급).
2026-05-24 13:25:38 +09:00

78 lines
3.5 KiB
Python

from fastapi import FastAPI, Depends, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, JSONResponse
from starlette.middleware.sessions import SessionMiddleware
import logging
import os
from app.database import engine, Base, check_db_connection, log_db_startup_status
from app.database_maintenance import ensure_search_optimizations
from app.routers import orders, settings
from app.auth import router as auth_router
logging.basicConfig(level=logging.INFO)
APP_ROOT_PATH = os.getenv("APP_ROOT_PATH", "").rstrip("/")
# Verify DB connectivity at startup (log only — do not crash so the
# container can stay up and report status via /health/db).
log_db_startup_status()
# Create all DB tables
Base.metadata.create_all(bind=engine)
ensure_search_optimizations(engine)
app = FastAPI(title="Order Management System", root_path=APP_ROOT_PATH)
@app.get("/health/db")
async def health_db():
ok, msg = check_db_connection()
status_code = 200 if ok else 503
return JSONResponse({"ok": ok, "detail": msg}, status_code=status_code)
# ---- Session middleware ----
# dbx-main 과 SSO 하려면 SESSION_SECRET_KEY 와 SESSION_COOKIE_NAME 을
# 두 앱이 동일하게 맞춰야 한다. 그래야 dbx-main 이 발급한 세션 쿠키를
# OMS 가 그대로 읽을 수 있다.
_session_secret = os.getenv("SESSION_SECRET_KEY", "").strip()
if not _session_secret:
raise RuntimeError(
"SESSION_SECRET_KEY 환경변수가 설정되지 않았습니다. "
"openssl rand -hex 32 로 새 값을 만들어 .env 에 넣고 컨테이너를 재기동하세요. "
"dbx-main 과 SSO 하려면 양쪽 .env 에 같은 값이어야 합니다."
)
app.add_middleware(
SessionMiddleware,
secret_key=_session_secret,
session_cookie=os.getenv("SESSION_COOKIE_NAME", "session"),
same_site=os.getenv("SESSION_SAME_SITE", "lax"),
https_only=os.getenv("SESSION_HTTPS_ONLY", "0") == "1",
max_age=int(os.getenv("SESSION_MAX_AGE", "28800")), # 8h — dbx-main 과 통일
)
# Include routers
app.include_router(auth_router)
app.include_router(orders.router, prefix="/api/orders", tags=["orders"])
app.include_router(settings.router, prefix="/api/settings", tags=["settings"])
# Mount static files for frontend
os.makedirs("static", exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/", response_class=HTMLResponse)
async def read_root():
# Return the main index.html file
if os.path.exists("static/index.html"):
with open("static/index.html", "r", encoding="utf-8") as f:
content = f.read()
content = content.replace("__APP_BASE_PATH__", APP_ROOT_PATH)
content = content.replace('src="/static/', f'src="{APP_ROOT_PATH}/static/' if APP_ROOT_PATH else 'src="/static/')
content = content.replace('href="/static/', f'href="{APP_ROOT_PATH}/static/' if APP_ROOT_PATH else 'href="/static/')
content = content.replace("window.location.href='/login", f"window.location.href='{APP_ROOT_PATH}/login")
content = content.replace('window.location.href="/login', f'window.location.href="{APP_ROOT_PATH}/login')
content = content.replace("window.location.href='/logout", f"window.location.href='{APP_ROOT_PATH}/logout")
content = content.replace('window.location.href="/logout', f'window.location.href="{APP_ROOT_PATH}/logout')
return HTMLResponse(content=content)
return HTMLResponse(content="<h1>Welcome. static/index.html is missing.</h1>")