Files
Hotel-Booking/client/ZUSTAND_AUTH_GUIDE.md
Iliyan Angelov 824eec6190 Hotel Booking
2025-11-16 14:19:13 +02:00

306 lines
6.7 KiB
Markdown

# useAuthStore - Zustand Authentication Store
## ✅ Hoàn thành Chức năng 3
### 📦 Files đã tạo:
1. **`src/store/useAuthStore.ts`** - Zustand store quản lý auth
2. **`src/services/api/apiClient.ts`** - Axios client với interceptors
3. **`src/services/api/authService.ts`** - Auth API service
4. **`.env.example`** - Template cho environment variables
### 🎯 Tính năng đã implement:
#### State Management:
```typescript
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:
```typescript
import useAuthStore from './store/useAuthStore';
function App() {
const {
isAuthenticated,
userInfo,
logout,
initializeAuth
} = useAuthStore();
useEffect(() => {
initializeAuth();
}, [initializeAuth]);
// ...
}
```
#### 2. Sử dụng trong Login Form:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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 token
- `refreshToken` - JWT refresh token
- `userInfo` - 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/`:
```env
VITE_API_URL=http://localhost:3000
VITE_ENV=development
```
#### API Endpoints được sử dụng:
- `POST /api/auth/login` - Đăng nhập
- `POST /api/auth/register` - Đăng ký
- `POST /api/auth/logout` - Đăng xuất
- `GET /api/auth/profile` - Lấy profile
- `POST /api/auth/refresh-token` - Refresh token
- `POST /api/auth/forgot-password` - Quên mật khẩu
- `POST /api/auth/reset-password` - Đặt lại mật khẩu
### 🛡️ Security Features:
1. **Auto Token Injection**:
- Axios interceptor tự động thêm token vào headers
```typescript
Authorization: Bearer <token>
```
2. **Auto Logout on 401**:
- Khi token hết hạn (401), tự động logout và redirect về login
3. **Token Refresh**:
- Có thể refresh token khi sắp hết hạn
4. **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:
```typescript
// TRƯỚC (với props)
<ProtectedRoute isAuthenticated={isAuthenticated}>
<Dashboard />
</ProtectedRoute>
// SAU (tự động lấy từ store)
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
```
#### AdminRoute:
```typescript
// 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:
```typescript
<LayoutMain
isAuthenticated={isAuthenticated}
userInfo={userInfo}
onLogout={handleLogout}
/>
```
### 🧪 Testing:
Để test authentication flow:
1. **Tạo file `.env`**:
```bash
cp .env.example .env
```
2. **Ensure backend đang chạy**:
```bash
cd server
npm run dev
```
3. **Chạy frontend**:
```bash
cd client
npm run dev
```
4. **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
### 🚀 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:
```typescript
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:
1. ✅ Toàn bộ thông tin user được quản lý tập trung
2. ✅ Duy trì đăng nhập sau khi reload trang
3. ✅ Dễ dàng truy cập userInfo trong mọi component
4. ✅ Auto token management
5. ✅ Type-safe với TypeScript
6. ✅ Clean code, dễ maintain