Add routes navigation login and admin dashboard
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
class ApiConfig {
|
||||
// static const String baseUrl = 'https://ynov.ptits-pas.fr/api/v1';
|
||||
static const String baseUrl = 'http://localhost:3000/api/v1';
|
||||
// static const String baseUrl = 'http://localhost:3000/api/v1/';
|
||||
static const String baseUrl = 'https://ynov.ptits-pas.fr/api/v1';
|
||||
|
||||
// Auth endpoints
|
||||
static const String login = '/auth/login';
|
||||
@@ -18,4 +18,15 @@ class ApiConfig {
|
||||
static const String contracts = '/contracts';
|
||||
static const String conversations = '/conversations';
|
||||
static const String notifications = '/notifications';
|
||||
|
||||
// Headers
|
||||
static Map<String, String> get headers => {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
|
||||
static Map<String, String> authHeaders(String token) => {
|
||||
...headers,
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class TokenService {
|
||||
static const _storage = FlutterSecureStorage();
|
||||
static const _tokenKey = 'access_token';
|
||||
static const String _refreshTokenKey = 'refresh_token';
|
||||
static const _roleKey = 'user_role';
|
||||
|
||||
// Stockage du token
|
||||
static Future<void> saveToken(String token) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_tokenKey, token);
|
||||
}
|
||||
|
||||
// Stockage du refresh token
|
||||
static Future<void> saveRefreshToken(String refreshToken) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_refreshTokenKey, refreshToken);
|
||||
}
|
||||
|
||||
// Stockage du rôle
|
||||
static Future<void> saveRole(String role) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_roleKey, role);
|
||||
}
|
||||
|
||||
// Récupération du token
|
||||
static Future<String?> getToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(_tokenKey);
|
||||
}
|
||||
|
||||
// Récupération du refresh token
|
||||
static Future<String?> getRefreshToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(_refreshTokenKey);
|
||||
}
|
||||
|
||||
// Récupération du rôle
|
||||
static Future<String?> getRole() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(_roleKey);
|
||||
}
|
||||
|
||||
// Suppression du token
|
||||
static Future<void> deleteToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_tokenKey);
|
||||
}
|
||||
|
||||
// Suppression du refresh token
|
||||
static Future<void> deleteRefreshToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_refreshTokenKey);
|
||||
}
|
||||
|
||||
|
||||
// Suppression du rôle
|
||||
static Future<void> deleteRole() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_roleKey);
|
||||
}
|
||||
|
||||
// Nettoyage complet
|
||||
static Future<void> clearAll() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_tokenKey);
|
||||
await prefs.remove(_refreshTokenKey);
|
||||
await prefs.remove(_roleKey);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,86 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:p_tits_pas/services/api/api_config.dart';
|
||||
import 'package:p_tits_pas/services/api/tokenService.dart';
|
||||
import '../models/user.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
|
||||
class AuthResponse {
|
||||
final String acessToken;
|
||||
final String role;
|
||||
|
||||
AuthResponse({required this.acessToken, required this.role});
|
||||
|
||||
factory AuthResponse.fromJson(Map<String, dynamic> json) {
|
||||
return AuthResponse(
|
||||
acessToken: json['acessToken'],
|
||||
role: json['role'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AuthService {
|
||||
ApiConfig apiConfig = ApiConfig();
|
||||
String baseUrl = ApiConfig.baseUrl;
|
||||
final storage = const FlutterSecureStorage();
|
||||
final String baseUrl = ApiConfig.baseUrl;
|
||||
|
||||
//login
|
||||
Future<AuthResponse> login(String email, String password) async {
|
||||
final response = await http.post(
|
||||
Uri.parse('$baseUrl${ApiConfig.login}'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({'email': email, 'password': password}),
|
||||
);
|
||||
Future<Map<String, dynamic>> login(String email, String password) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('$baseUrl${ApiConfig.login}'),
|
||||
headers: ApiConfig.headers,
|
||||
body: jsonEncode({
|
||||
'email': email,
|
||||
'password': password
|
||||
}),
|
||||
);
|
||||
if (response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
final authResponse = AuthResponse.fromJson(data);
|
||||
await TokenService.saveToken(data['access_token']);
|
||||
await TokenService.saveRefreshToken(data['refresh_token']);
|
||||
final role = _extractRoleFromToken(data['access_token']);
|
||||
await TokenService.saveRole(role);
|
||||
|
||||
await storage.write(key: 'access_token', value: authResponse.acessToken);
|
||||
await storage.write(key: 'role', value: authResponse.role);
|
||||
return authResponse;
|
||||
} else {
|
||||
throw Exception('Failed to login');
|
||||
return data;
|
||||
} else {
|
||||
throw Exception('Failed to login: ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Failed to login: $e');
|
||||
}
|
||||
}
|
||||
|
||||
String _extractRoleFromToken(String token) {
|
||||
try {
|
||||
final parts = token.split('.');
|
||||
if (parts.length != 3) return '';
|
||||
|
||||
final payload = parts[1];
|
||||
final normalizedPayload = base64Url.normalize(payload);
|
||||
final decoded = utf8.decode(base64Url.decode(normalizedPayload));
|
||||
final Map<String, dynamic> payloadMap = jsonDecode(decoded);
|
||||
|
||||
return payloadMap['role'] ?? '';
|
||||
} catch (e) {
|
||||
print('Error extracting role from token: $e');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
await TokenService.clearAll();
|
||||
}
|
||||
|
||||
Future<bool> isAuthenticated() async {
|
||||
final token = await TokenService.getToken();
|
||||
if (token == null) return false;
|
||||
|
||||
return !_isTokenExpired(token);
|
||||
}
|
||||
|
||||
bool _isTokenExpired(String token) {
|
||||
try {
|
||||
final parts = token.split('.');
|
||||
if (parts.length != 3) return true;
|
||||
|
||||
final payload = parts[1];
|
||||
final normalizedPayload = base64Url.normalize(payload);
|
||||
final decoded = utf8.decode(base64Url.decode(normalizedPayload));
|
||||
final Map<String, dynamic> payloadMap = jsonDecode(decoded);
|
||||
|
||||
final exp = payloadMap['exp'];
|
||||
if (exp == null) return true;
|
||||
|
||||
final expirationDate = DateTime.fromMillisecondsSinceEpoch(exp * 1000);
|
||||
return DateTime.now().isAfter(expirationDate);
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user