Files
minhthu/lib/features/auth/QUICK_REFERENCE.md
2025-10-28 00:09:46 +07:00

253 lines
5.4 KiB
Markdown

# Authentication Feature - Quick Reference
## Import
```dart
import 'package:minhthu/features/auth/auth.dart';
```
## Common Usage Patterns
### 1. Login
```dart
ref.read(authProvider.notifier).login(username, password);
```
### 2. Logout
```dart
ref.read(authProvider.notifier).logout();
```
### 3. Check if Authenticated
```dart
final isAuthenticated = ref.watch(isAuthenticatedProvider);
```
### 4. Get Current User
```dart
final user = ref.watch(currentUserProvider);
if (user != null) {
print('Logged in as: ${user.username}');
}
```
### 5. Watch Auth State
```dart
final authState = ref.watch(authProvider);
if (authState.isLoading) {
return LoadingIndicator();
}
if (authState.error != null) {
return ErrorView(message: authState.error!);
}
if (authState.isAuthenticated) {
return HomeView(user: authState.user!);
}
return LoginView();
```
### 6. Listen to Auth Changes
```dart
ref.listen(authProvider, (previous, next) {
if (next.isAuthenticated) {
context.go('/home');
} else if (next.error != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(next.error!)),
);
}
});
```
## Key Classes
### AuthState
```dart
class AuthState {
final UserEntity? user;
final bool isAuthenticated;
final bool isLoading;
final String? error;
}
```
### UserEntity
```dart
class UserEntity {
final String userId;
final String username;
final String accessToken;
final String? refreshToken;
}
```
### LoginRequestModel
```dart
final request = LoginRequestModel(
username: 'john.doe',
password: 'secure123',
);
```
## Providers
| Provider | Type | Description |
|----------|------|-------------|
| `authProvider` | `StateNotifier<AuthState>` | Main auth state |
| `isAuthenticatedProvider` | `bool` | Check auth status |
| `currentUserProvider` | `UserEntity?` | Get current user |
| `isAuthLoadingProvider` | `bool` | Check loading state |
| `authErrorProvider` | `String?` | Get error message |
## API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/auth/login` | POST | Login |
| `/api/v1/auth/logout` | POST | Logout |
| `/api/v1/auth/refresh` | POST | Refresh token |
## Error Types
- `ValidationFailure` - Invalid input
- `AuthenticationFailure` - Login failed
- `NetworkFailure` - Network error
- `ServerFailure` - Server error
## Protected Route Example
```dart
class MyPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final authState = ref.watch(authProvider);
if (!authState.isAuthenticated) {
return LoginPage();
}
return Scaffold(
appBar: AppBar(
title: Text('Protected Page'),
actions: [
IconButton(
icon: Icon(Icons.logout),
onPressed: () => ref.read(authProvider.notifier).logout(),
),
],
),
body: Center(
child: Text('Hello, ${authState.user!.username}!'),
),
);
}
}
```
## Common Patterns
### Check Auth on App Start
```dart
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(authProvider.notifier).checkAuthStatus();
});
}
```
### Show Loading Overlay
```dart
if (ref.watch(isAuthLoadingProvider)) {
return Stack(
children: [
yourContent,
LoadingIndicator.overlay(),
],
);
}
```
### Conditional Navigation
```dart
ref.listen(authProvider, (previous, next) {
if (!previous!.isAuthenticated && next.isAuthenticated) {
context.go('/home');
} else if (previous.isAuthenticated && !next.isAuthenticated) {
context.go('/login');
}
});
```
## Testing Helpers
```dart
// Mock auth state
final mockAuthState = AuthState.authenticated(
UserEntity(
userId: '123',
username: 'test',
accessToken: 'token',
),
);
// Create test container
final container = ProviderContainer(
overrides: [
authProvider.overrideWith((ref) => MockAuthNotifier()),
],
);
```
## Files Reference
| Layer | File | Purpose |
|-------|------|---------|
| **Data** | `login_request_model.dart` | Request DTO |
| | `user_model.dart` | User DTO |
| | `auth_remote_datasource.dart` | API calls |
| | `auth_repository_impl.dart` | Repository impl |
| **Domain** | `user_entity.dart` | Domain entity |
| | `auth_repository.dart` | Repository interface |
| | `login_usecase.dart` | Business logic |
| **Presentation** | `login_page.dart` | Login UI |
| | `login_form.dart` | Form widget |
| | `auth_provider.dart` | State management |
| **DI** | `auth_dependency_injection.dart` | Providers setup |
## Troubleshooting Quick Fixes
| Issue | Solution |
|-------|----------|
| Provider not found | Add `ProviderScope` to main.dart |
| Navigation fails | Check router configuration |
| Tokens not saved | Verify secure storage setup |
| API calls fail | Check base URL in constants |
| State not updating | Use `ConsumerWidget` |
## Performance Tips
1. Use `ref.read()` for one-time operations
2. Use `ref.watch()` for reactive updates
3. Use `ref.listen()` for side effects
4. Avoid rebuilding entire tree - scope providers
5. Use `select()` for partial state watching
## Security Checklist
- [x] Tokens in secure storage
- [x] Password fields obscured
- [x] No logging of sensitive data
- [x] Token auto-added to headers
- [x] Token cleared on logout
- [x] Input validation
- [ ] HTTPS only (configure in production)
- [ ] Token expiration handling
- [ ] Rate limiting
- [ ] Biometric auth (optional)