5.4 KiB
5.4 KiB
Authentication Feature - Quick Reference
Import
import 'package:minhthu/features/auth/auth.dart';
Common Usage Patterns
1. Login
ref.read(authProvider.notifier).login(username, password);
2. Logout
ref.read(authProvider.notifier).logout();
3. Check if Authenticated
final isAuthenticated = ref.watch(isAuthenticatedProvider);
4. Get Current User
final user = ref.watch(currentUserProvider);
if (user != null) {
print('Logged in as: ${user.username}');
}
5. Watch Auth State
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
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
class AuthState {
final UserEntity? user;
final bool isAuthenticated;
final bool isLoading;
final String? error;
}
UserEntity
class UserEntity {
final String userId;
final String username;
final String accessToken;
final String? refreshToken;
}
LoginRequestModel
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 inputAuthenticationFailure- Login failedNetworkFailure- Network errorServerFailure- Server error
Protected Route Example
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
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(authProvider.notifier).checkAuthStatus();
});
}
Show Loading Overlay
if (ref.watch(isAuthLoadingProvider)) {
return Stack(
children: [
yourContent,
LoadingIndicator.overlay(),
],
);
}
Conditional Navigation
ref.listen(authProvider, (previous, next) {
if (!previous!.isAuthenticated && next.isAuthenticated) {
context.go('/home');
} else if (previous.isAuthenticated && !next.isAuthenticated) {
context.go('/login');
}
});
Testing Helpers
// 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
- Use
ref.read()for one-time operations - Use
ref.watch()for reactive updates - Use
ref.listen()for side effects - Avoid rebuilding entire tree - scope providers
- Use
select()for partial state watching
Security Checklist
- Tokens in secure storage
- Password fields obscured
- No logging of sensitive data
- Token auto-added to headers
- Token cleared on logout
- Input validation
- HTTPS only (configure in production)
- Token expiration handling
- Rate limiting
- Biometric auth (optional)