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
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
|