From 3ab8c795f715f74eb61e4e9c3fff5732eeaf0749 Mon Sep 17 00:00:00 2001 From: shuim Date: Mon, 21 Sep 2026 10:32:06 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=AA=A8=EB=8D=B8=20=EB=B6=84=EB=A6=AC=20=E2=80=94?= =?UTF-8?q?=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EA=B8=B8=EC=9D=B4=20?= =?UTF-8?q?=EC=A0=95=EC=B1=85=EC=9D=80=20=EA=B0=80=EC=9E=85=20=EC=8B=9C?= =?UTF-8?q?=EC=97=90=EB=A7=8C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인이 회원가입용 Credentials(8자 이상)를 공유해 부트스트랩 admin 계정(짧은 비밀번호)이 422 로 거부됨. LoginRequest(min_length=1) 신설, 조회 시 username strip. Co-Authored-By: Claude Opus 5 (1M context) --- backend/app/api/endpoints/auth.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/app/api/endpoints/auth.py b/backend/app/api/endpoints/auth.py index 65706ca..8948855 100644 --- a/backend/app/api/endpoints/auth.py +++ b/backend/app/api/endpoints/auth.py @@ -66,6 +66,12 @@ class Credentials(BaseModel): return v +class LoginRequest(BaseModel): + """로그인 요청 — 길이 정책은 가입 시에만 적용(부트스트랩 시드 계정 등 짧은 비밀번호 허용).""" + username: str = Field(..., min_length=1, max_length=32) + password: str = Field(..., min_length=1, max_length=128) + + class LoginResponse(BaseModel): token: str expires_at: datetime @@ -213,7 +219,7 @@ async def register(body: Credentials, request: Request, db: AsyncSession = Depen @router.post("/login", response_model=LoginResponse) -async def login(body: Credentials, request: Request, db: AsyncSession = Depends(get_db)): +async def login(body: LoginRequest, request: Request, db: AsyncSession = Depends(get_db)): ip = _client_ip(request) remaining = _lockout_remaining(ip) if remaining > 0: @@ -222,7 +228,7 @@ async def login(body: Credentials, request: Request, db: AsyncSession = Depends( detail=f"로그인 시도가 너무 많습니다. {remaining}초 후 다시 시도하세요.", ) - user = (await db.execute(select(User).where(User.username == body.username))).scalar_one_or_none() + user = (await db.execute(select(User).where(User.username == body.username.strip()))).scalar_one_or_none() # 존재하지 않는 계정도 해시 검증을 수행해 응답 시간 차이로 계정 유무가 드러나지 않게 함 pw_ok = await _check_password_async(body.password, user.password_hash if user else _DUMMY_HASH)