From 961be91a8a2607206faf40c38b5555a8d941bb84 Mon Sep 17 00:00:00 2001 From: host Date: Mon, 10 Aug 2026 00:51:21 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D1=8C=20?= =?UTF-8?q?=D0=BF=D1=83=D0=B1=D0=BB=D0=B8=D1=87=D0=BD=D1=83=D1=8E=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8=D1=8E.?= =?UTF-8?q?=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20=E2=80=94=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE?= =?UTF-8?q?=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20CLI=20=D0=B8=D0=BB=D0=B8=20?= =?UTF-8?q?=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/routers/auth.py | 43 +++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/backend/app/routers/auth.py b/backend/app/routers/auth.py index 6d25437..1bdbdb5 100644 --- a/backend/app/routers/auth.py +++ b/backend/app/routers/auth.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.orm import Session @@ -12,21 +12,34 @@ router = APIRouter(prefix="/auth", tags=["auth"]) @router.post("/register", response_model=schemas.UserOut) def register(payload: schemas.UserCreate, db: Session = Depends(get_db)): - existing = db.query(models.User).filter(models.User.email == payload.email).first() - if existing: - raise HTTPException(status_code=400, detail="Пользователь с таким email уже существует") + """Регистрация закрыта для публичного доступа. - # первый зарегистрированный пользователь становится администратором - is_first_user = db.query(models.User).count() == 0 - user = models.User( - email=payload.email, - password_hash=hash_password(payload.password), - role=models.Role.admin if is_first_user else models.Role.client, + Единственное исключение — bootstrap первого администратора: когда в БД + ещё нет ни одного пользователя, регистрация создаёт admin-аккаунт. Это + нужно, чтобы панель можно было поднять с нуля. Все последующие + пользователи создаются только через CLI (`python -m app.manage_users`) + или админский эндпоинт /admin/users. + """ + email = payload.email.lower().strip() + + # Bootstrap: первый пользователь становится администратором. + if db.query(models.User).count() == 0: + user = models.User( + email=email, + password_hash=hash_password(payload.password), + role=models.Role.admin, + is_active=True, + ) + db.add(user) + db.commit() + db.refresh(user) + return user + + # Публичная регистрация закрыта — отвечаем 403. + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Регистрация закрыта. Обратитесь к администратору для создания учётной записи.", ) - db.add(user) - db.commit() - db.refresh(user) - return user @router.post("/login", response_model=schemas.Token) @@ -34,6 +47,8 @@ def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depend user = db.query(models.User).filter(models.User.email == form_data.username).first() if not user or not verify_password(form_data.password, user.password_hash): raise HTTPException(status_code=401, detail="Неверный email или пароль") + if not user.is_active: + raise HTTPException(status_code=403, detail="Аккаунт деактивирован. Обратитесь к администратору.") token = create_access_token({"sub": str(user.id)}) return {"access_token": token, "token_type": "bearer"}