first commit
This commit is contained in:
commit
efa5080897
127 changed files with 18610 additions and 0 deletions
63
backend/app/api_key_auth.py
Normal file
63
backend/app/api_key_auth.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import Depends, Header, HTTPException, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
|
||||
from .api_keys_service import KEY_PREFIX, parse_api_token, verify_api_token
|
||||
from .database import get_db
|
||||
from .models import ApiKey, UserAccount
|
||||
|
||||
|
||||
def _extract_api_key(
|
||||
authorization: str | None,
|
||||
x_api_key: str | None,
|
||||
) -> str | None:
|
||||
if x_api_key:
|
||||
return x_api_key.strip()
|
||||
if authorization and authorization.lower().startswith("bearer "):
|
||||
return authorization[7:].strip()
|
||||
return None
|
||||
|
||||
|
||||
def current_api_key(
|
||||
authorization: str | None = Header(default=None),
|
||||
x_api_key: str | None = Header(default=None, alias="X-Api-Key"),
|
||||
db: Session = Depends(get_db),
|
||||
) -> ApiKey:
|
||||
token = _extract_api_key(authorization, x_api_key)
|
||||
if not token or not token.startswith(KEY_PREFIX):
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Valid API key required")
|
||||
|
||||
parsed = parse_api_token(token)
|
||||
if parsed:
|
||||
key_id, _ = parsed
|
||||
api_key = db.scalar(
|
||||
select(ApiKey)
|
||||
.options(joinedload(ApiKey.user))
|
||||
.where(ApiKey.id == key_id, ApiKey.revoked_at.is_(None))
|
||||
)
|
||||
if api_key and verify_api_token(token, api_key.key_hash):
|
||||
api_key.last_used_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
return api_key
|
||||
|
||||
active_keys = db.scalars(
|
||||
select(ApiKey)
|
||||
.options(joinedload(ApiKey.user))
|
||||
.where(ApiKey.revoked_at.is_(None))
|
||||
).all()
|
||||
for api_key in active_keys:
|
||||
if verify_api_token(token, api_key.key_hash):
|
||||
api_key.last_used_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
return api_key
|
||||
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key")
|
||||
|
||||
|
||||
def current_api_user(api_key: ApiKey = Depends(current_api_key)) -> UserAccount:
|
||||
if api_key.user.status != "active":
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Account unavailable")
|
||||
return api_key.user
|
||||
Loading…
Add table
Add a link
Reference in a new issue