diff --git a/backend/app/core/security.py b/backend/app/core/security.py index be5ce5a..56de4e9 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -1,20 +1,19 @@ +import bcrypt + from datetime import datetime, timedelta, timezone from typing import Any from jose import jwt -from passlib.context import CryptContext from app.core.config import settings -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") - def verify_password(plain_password: str, hashed_password: str) -> bool: - return pwd_context.verify(plain_password, hashed_password) + return bcrypt.checkpw(plain_password.encode("utf-8"), hashed_password.encode("utf-8")) def get_password_hash(password: str) -> str: - return pwd_context.hash(password) + return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") def create_access_token(subject: str, expires_delta: timedelta | None = None) -> str: diff --git a/backend/requirements.txt b/backend/requirements.txt index 8098fe9..8040059 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -6,7 +6,6 @@ alembic==1.14.0 pydantic==2.10.3 pydantic-settings==2.6.1 python-jose[cryptography]==3.3.0 -passlib[bcrypt]==1.7.4 bcrypt==4.2.1 python-multipart==0.0.20 httpx==0.28.1 diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 379256a..bdfb58f 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -1,8 +1,18 @@ import { LockOutlined, UserOutlined } from '@ant-design/icons' import { Button, Card, Form, Input, Tabs, Typography, message } from 'antd' +import axios from 'axios' import { Navigate, useNavigate } from 'react-router-dom' import { useAuth } from '../context/AuthContext' +function apiErrorMessage(error: unknown, fallback: string) { + if (axios.isAxiosError(error)) { + const detail = error.response?.data?.detail + if (typeof detail === 'string') return detail + if (Array.isArray(detail) && detail[0]?.msg) return detail[0].msg + } + return fallback +} + export default function LoginPage() { const { user, login, register, loading } = useAuth() const navigate = useNavigate() @@ -16,8 +26,8 @@ export default function LoginPage() { await login(values.username, values.password) message.success('登录成功') navigate('/') - } catch { - message.error('用户名或密码错误') + } catch (error) { + message.error(apiErrorMessage(error, '用户名或密码错误')) } } @@ -30,8 +40,8 @@ export default function LoginPage() { await register(values.username, values.password) message.success('注册成功') navigate('/') - } catch { - message.error('注册失败,用户名可能已存在') + } catch (error) { + message.error(apiErrorMessage(error, '注册失败,请稍后重试')) } }