Initial scaffold: FastAPI backend + Vue 3 frontend + Docker setup
Backend: config/db/security/logging core, SQLAlchemy models (Server, Credential, UpdateJob, UpdateLog, AuditLog, User), services (winrm, ssh, cau, audit, job_runner), REST API (auth, servers, updates, audit), Socket.io WebSocket layer. Frontend: Vue 3 + TS + Pinia + Tailwind, Views (Dashboard, Servers, Updates, Audit, Login), axios + socket.io-client, nginx prod config.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""Auth routes: login (local user or LDAP stub)."""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import client_ip
|
||||
from app.core.config import get_settings
|
||||
from app.core.database import get_db
|
||||
from app.core.exceptions import UnauthorizedError
|
||||
from app.core.security import create_access_token, verify_password
|
||||
from app.models.user import User
|
||||
from app.schemas.auth import LoginRequest, TokenResponse
|
||||
from app.services.audit import AuditService
|
||||
|
||||
settings = get_settings()
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
async def login(
|
||||
payload: LoginRequest,
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> TokenResponse:
|
||||
audit = AuditService(db)
|
||||
result = await db.execute(select(User).where(User.username == payload.username))
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if user and user.password_hash and verify_password(payload.password, user.password_hash):
|
||||
user.last_login_at = datetime.now(UTC)
|
||||
await audit.log(
|
||||
username=user.username,
|
||||
action="auth.login",
|
||||
ip_address=client_ip(request),
|
||||
)
|
||||
token = create_access_token(
|
||||
subject=user.username,
|
||||
extra_claims={"is_admin": user.is_admin},
|
||||
)
|
||||
return TokenResponse(
|
||||
access_token=token,
|
||||
expires_in=settings.jwt_access_token_expire_minutes * 60,
|
||||
)
|
||||
|
||||
# LDAP stub: when enabled, attempt bind + search here (not yet implemented)
|
||||
await audit.log(
|
||||
username=payload.username,
|
||||
action="auth.login",
|
||||
result="failure",
|
||||
ip_address=client_ip(request),
|
||||
)
|
||||
raise UnauthorizedError("Benutzername oder Passwort falsch")
|
||||
Reference in New Issue
Block a user