feat(frontend): init Flutter project with login screen and JWT auth
- Projet Flutter créé manuellement (pubspec.yaml, structure lib/) - Écran de connexion complet avec validation, gestion erreurs, spinner - ApiClient Dio avec intercepteur JWT automatique - AuthProvider (Provider) + AuthService (shared_preferences) - Routing GoRouter avec redirection auth/non-auth - DashboardScreen placeholder - Rapport PFE : ajout Chapitre 5 Frontend (architecture, JWT, login) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class ApiClient {
|
||||
static const String baseUrl = 'http://192.168.100.33:8090/api';
|
||||
|
||||
static final Dio _dio = Dio(BaseOptions(
|
||||
baseUrl: baseUrl,
|
||||
connectTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
))
|
||||
..interceptors.add(_AuthInterceptor());
|
||||
|
||||
static Dio get instance => _dio;
|
||||
}
|
||||
|
||||
class _AuthInterceptor extends Interceptor {
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final token = prefs.getString('jwt_token');
|
||||
if (token != null) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
handler.next(options);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
handler.next(err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'api_client.dart';
|
||||
|
||||
class AuthService {
|
||||
static Future<Map<String, dynamic>> login(String username, String password) async {
|
||||
final response = await ApiClient.instance.post('/auth/signin', data: {
|
||||
'username': username,
|
||||
'password': password,
|
||||
});
|
||||
return response.data as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
static Future<void> saveToken(String token, String role) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('jwt_token', token);
|
||||
await prefs.setString('user_role', role);
|
||||
}
|
||||
|
||||
static Future<String?> getToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString('jwt_token');
|
||||
}
|
||||
|
||||
static Future<String?> getRole() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString('user_role');
|
||||
}
|
||||
|
||||
static Future<void> logout() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove('jwt_token');
|
||||
await prefs.remove('user_role');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user