45 lines
1.8 KiB
Python
Raw Normal View History

2025-12-10 12:02:17 +08:00
from datetime import datetime, timezone
from fastapi import HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from backend.core.security import create_access_token, verify_password
from backend.modules.audit.models import AuditAction, AuditLog, AuditResourceType
from backend.modules.users.models import User
async def authenticate_user(session: AsyncSession, username: str, password: str) -> User:
user = await session.scalar(
select(User).where(User.username == username).options(selectinload(User.role), selectinload(User.customer))
)
if not user or not verify_password(password, user.password_hash):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User disabled")
user.last_login_at = datetime.now(timezone.utc)
await session.commit()
await session.refresh(user)
return user
async def create_login_audit(session: AsyncSession, user: User, request) -> None:
audit = AuditLog(
user_id=user.id,
customer_id=user.customer_id,
action=AuditAction.LOGIN,
resource_type=AuditResourceType.USER,
resource_id=user.id,
description="User login success",
ip_address=request.client.host if request and request.client else None,
user_agent=request.headers.get("User-Agent") if request else None,
)
session.add(audit)
await session.commit()
def build_access_token(user: User) -> str:
payload = {"sub": str(user.id), "role": user.role.name if user.role else "", "customer_id": user.customer_id}
return create_access_token(payload)