6.7 KiB
6.7 KiB
useAuthStore - Zustand Authentication Store
✅ Hoàn thành Chức năng 3
📦 Files đã tạo:
src/store/useAuthStore.ts- Zustand store quản lý authsrc/services/api/apiClient.ts- Axios client với interceptorssrc/services/api/authService.ts- Auth API service.env.example- Template cho environment variables
🎯 Tính năng đã implement:
State Management:
interface AuthState {
token: string | null;
refreshToken: string | null;
userInfo: UserInfo | null;
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
}
Actions:
- ✅
login(credentials)- Đăng nhập - ✅
register(data)- Đăng ký tài khoản mới - ✅
logout()- Đăng xuất - ✅
setUser(user)- Cập nhật thông tin user - ✅
refreshAuthToken()- Làm mới token - ✅
forgotPassword(data)- Quên mật khẩu - ✅
resetPassword(data)- Đặt lại mật khẩu - ✅
initializeAuth()- Khởi tạo auth từ localStorage - ✅
clearError()- Xóa error message
📝 Cách sử dụng:
1. Khởi tạo trong App.tsx:
import useAuthStore from './store/useAuthStore';
function App() {
const {
isAuthenticated,
userInfo,
logout,
initializeAuth
} = useAuthStore();
useEffect(() => {
initializeAuth();
}, [initializeAuth]);
// ...
}
2. Sử dụng trong Login Form:
import useAuthStore from '../store/useAuthStore';
const LoginPage = () => {
const { login, isLoading, error } = useAuthStore();
const navigate = useNavigate();
const handleSubmit = async (data) => {
try {
await login(data);
navigate('/dashboard'); // Redirect sau khi login
} catch (error) {
// Error đã được xử lý bởi store
}
};
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
{error && <div>{error}</div>}
<button disabled={isLoading}>
{isLoading ? 'Đang xử lý...' : 'Đăng nhập'}
</button>
</form>
);
};
3. Sử dụng trong Register Form:
const RegisterPage = () => {
const { register, isLoading } = useAuthStore();
const navigate = useNavigate();
const handleSubmit = async (data) => {
try {
await register(data);
navigate('/login'); // Redirect về login
} catch (error) {
// Error được hiển thị qua toast
}
};
// ...
};
4. Logout:
const Header = () => {
const { logout } = useAuthStore();
const handleLogout = async () => {
await logout();
// Auto redirect về login nếu cần
};
return <button onClick={handleLogout}>Đăng xuất</button>;
};
5. Hiển thị thông tin user:
const Profile = () => {
const { userInfo } = useAuthStore();
return (
<div>
<h1>Xin chào, {userInfo?.name}</h1>
<p>Email: {userInfo?.email}</p>
<p>Role: {userInfo?.role}</p>
</div>
);
};
🔐 LocalStorage Persistence:
Store tự động lưu và đọc từ localStorage:
token- JWT access tokenrefreshToken- JWT refresh tokenuserInfo- Thông tin user
Khi reload page, auth state được khôi phục tự động qua initializeAuth().
🌐 API Integration:
Base URL Configuration:
Tạo file .env trong thư mục client/:
VITE_API_URL=http://localhost:3000
VITE_ENV=development
API Endpoints được sử dụng:
POST /api/auth/login- Đăng nhậpPOST /api/auth/register- Đăng kýPOST /api/auth/logout- Đăng xuấtGET /api/auth/profile- Lấy profilePOST /api/auth/refresh-token- Refresh tokenPOST /api/auth/forgot-password- Quên mật khẩuPOST /api/auth/reset-password- Đặt lại mật khẩu
🛡️ Security Features:
-
Auto Token Injection:
- Axios interceptor tự động thêm token vào headers
Authorization: Bearer <token> -
Auto Logout on 401:
- Khi token hết hạn (401), tự động logout và redirect về login
-
Token Refresh:
- Có thể refresh token khi sắp hết hạn
-
Password Hashing:
- Backend xử lý bcrypt hashing
📱 Toast Notifications:
Store tự động hiển thị toast cho các events:
- ✅ Login thành công
- ✅ Đăng ký thành công
- ✅ Logout
- ❌ Login thất bại
- ❌ Đăng ký thất bại
- ❌ API errors
🔄 Component Updates:
ProtectedRoute:
// TRƯỚC (với props)
<ProtectedRoute isAuthenticated={isAuthenticated}>
<Dashboard />
</ProtectedRoute>
// SAU (tự động lấy từ store)
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
AdminRoute:
// TRƯỚC (với props)
<AdminRoute userInfo={userInfo}>
<AdminPanel />
</AdminRoute>
// SAU (tự động lấy từ store)
<AdminRoute>
<AdminPanel />
</AdminRoute>
LayoutMain:
Vẫn nhận props từ App.tsx để hiển thị Header/Navbar:
<LayoutMain
isAuthenticated={isAuthenticated}
userInfo={userInfo}
onLogout={handleLogout}
/>
🧪 Testing:
Để test authentication flow:
-
Tạo file
.env:cp .env.example .env -
Ensure backend đang chạy:
cd server npm run dev -
Chạy frontend:
cd client npm run dev -
Test flow:
- Truy cập
/register→ Đăng ký tài khoản - Truy cập
/login→ Đăng nhập - Truy cập
/dashboard→ Xem dashboard (protected) - Click logout → Xóa session
- Reload page → Auth state được khôi phục
- Truy cập
🚀 Next Steps:
Chức năng 4: Form Login
- Tạo LoginPage với React Hook Form + Yup
- Tích hợp với useAuthStore
- UX enhancements (loading, show/hide password, remember me)
Chức năng 5: Form Register
- Tạo RegisterPage với validation
- Tích hợp với useAuthStore
Chức năng 6-7: Password Reset Flow
- ForgotPasswordPage
- ResetPasswordPage
📚 TypeScript Types:
interface LoginCredentials {
email: string;
password: string;
rememberMe?: boolean;
}
interface RegisterData {
name: string;
email: string;
password: string;
phone?: string;
}
interface UserInfo {
id: number;
name: string;
email: string;
phone?: string;
avatar?: string;
role: string;
createdAt?: string;
}
✅ Kết quả đạt được:
- ✅ Toàn bộ thông tin user được quản lý tập trung
- ✅ Duy trì đăng nhập sau khi reload trang
- ✅ Dễ dàng truy cập userInfo trong mọi component
- ✅ Auto token management
- ✅ Type-safe với TypeScript
- ✅ Clean code, dễ maintain