feat: initial Jimi Gallery prototype
- Public site (Home/Artists/Exhibitions/News/About/Contact) with EN/KO/JA i18n - Admin panel with login, CRUD, image upload, multilingual editing - Exhibition slider/lightbox view - FastAPI + MongoDB backend, JWT auth - Docker Compose deployment, behind nginx at jimi.yakenator.io
This commit is contained in:
37
backend/auth.py
Normal file
37
backend/auth.py
Normal file
@ -0,0 +1,37 @@
|
||||
"""Admin auth: bcrypt-less password check + JWT issuance and verification."""
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import jwt
|
||||
from fastapi import Header, HTTPException
|
||||
|
||||
ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "admin")
|
||||
JWT_SECRET = os.environ.get("JWT_SECRET", "dev-secret-change-me")
|
||||
JWT_ALGO = "HS256"
|
||||
TOKEN_TTL_HOURS = int(os.environ.get("JWT_TTL_HOURS", "24"))
|
||||
|
||||
|
||||
def issue_token() -> str:
|
||||
payload = {
|
||||
"sub": "admin",
|
||||
"iat": datetime.now(timezone.utc),
|
||||
"exp": datetime.now(timezone.utc) + timedelta(hours=TOKEN_TTL_HOURS),
|
||||
}
|
||||
return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGO)
|
||||
|
||||
|
||||
def verify_token(token: str) -> bool:
|
||||
try:
|
||||
jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
async def require_auth(authorization: str = Header(default=None)):
|
||||
if not authorization or not authorization.lower().startswith("bearer "):
|
||||
raise HTTPException(status_code=401, detail="Missing bearer token")
|
||||
token = authorization.split(" ", 1)[1].strip()
|
||||
if not verify_token(token):
|
||||
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
||||
return True
|
||||
Reference in New Issue
Block a user