42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""자체 세션 토큰
|
|
구글 검증을 통과한 뒤로는 이걸 HttpOnly 쿠키로 들고 다닌다
|
|
|
|
담는 것은 user.id 하나다. 이메일·이름은 바뀔 수 있어 토큰에 넣지 않고 매번 DB에서 읽는다.
|
|
"""
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
from jose import JWTError, jwt
|
|
|
|
from settings import settings
|
|
|
|
ALGORITHM = "HS256"
|
|
COOKIE_NAME = "poster_alive_session"
|
|
|
|
|
|
class SessionInvalid(RuntimeError):
|
|
"""서명이 안 맞거나 만료됨"""
|
|
|
|
|
|
def issue(user_id: str) -> str:
|
|
if not settings.jwt_secret:
|
|
raise RuntimeError("JWT_SECRET 없음 — 세션을 발급할 수 없습니다")
|
|
expires = datetime.now(timezone.utc) + timedelta(days=settings.jwt_days)
|
|
return jwt.encode({"sub": user_id, "exp": expires}, settings.jwt_secret,
|
|
algorithm=ALGORITHM)
|
|
|
|
|
|
def read(token: str) -> str:
|
|
"""토큰에서 user.id를 꺼낸다"""
|
|
try:
|
|
claims = jwt.decode(token, settings.jwt_secret, algorithms=[ALGORITHM])
|
|
except JWTError as failure:
|
|
raise SessionInvalid("세션이 유효하지 않습니다") from failure
|
|
user_id = str(claims.get("sub") or "")
|
|
if not user_id:
|
|
raise SessionInvalid("sub 없음")
|
|
return user_id
|
|
|
|
|
|
def cookie_max_age() -> int:
|
|
return settings.jwt_days * 24 * 3600
|