You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
2.3 KiB
Python

# backend/app/auth/deps.py — 인증 의존성 (데모 모드 우회 포함)
from datetime import UTC, datetime
from fastapi import Depends, HTTPException, Request
from sqlmodel import Session, select
from ..config import get_settings
from ..db import get_session
from ..models import ApiToken, AuthSession, Person, UserCredential
from .tokens import hash_token, unsign_session_id
DEMO_USER_ID = "jiwoo" # AUTH_ENABLED=false 일 때 고정 사용자(데모 무손상)
def current_user(request: Request, session: Session = Depends(get_session)) -> Person:
st = get_settings()
# 1) 데모 모드: 인증 끔 → 항상 지우
if not st.auth_enabled:
user = session.get(Person, DEMO_USER_ID)
if user is None:
raise HTTPException(500, "demo user 'jiwoo' missing — run_seed 필요")
return user
# 2) 쿠키 세션(웹) 우선
raw = request.cookies.get(st.session_cookie_name)
if raw:
sid = unsign_session_id(raw)
if sid:
sess = session.get(AuthSession, sid)
if sess and not sess.revoked:
exp = sess.expires_at
if exp.tzinfo is None: # SQLite 는 naive 로 저장 → UTC 로 정규화
exp = exp.replace(tzinfo=UTC)
if exp > datetime.now(UTC):
u = session.get(Person, sess.user_id)
if u:
return u
# 3) 베어러 토큰(스크립트/모바일)
auth = request.headers.get("Authorization", "")
if auth.startswith("Bearer "):
th = hash_token(auth[7:])
tok = session.exec(select(ApiToken).where(ApiToken.token_hash == th)).first()
if tok and not tok.revoked:
tok.last_used_at = datetime.now(UTC)
session.add(tok)
session.commit()
u = session.get(Person, tok.user_id)
if u:
return u
raise HTTPException(status_code=401, detail="인증이 필요해요")
def require_admin(
user: Person = Depends(current_user), session: Session = Depends(get_session)
) -> Person:
cred = session.exec(select(UserCredential).where(UserCredential.user_id == user.id)).first()
if not cred or cred.role != "admin":
raise HTTPException(403, "관리자만 접근할 수 있어요")
return user