Flutter Secure Storage
Flutter Secure Storage
Section titled “Flutter Secure Storage”Pour stocker des données sensibles comme les tokens d’authentification, mots de passe, clés API, utilisez Flutter Secure Storage qui chiffre les données.
Installation
Section titled “Installation”dependencies: flutter_secure_storage: ^9.0.0Configuration Android
Section titled “Configuration Android”Dans android/app/build.gradle :
android { compileSdkVersion 33 // ...}Configuration et Utilisation
Section titled “Configuration et Utilisation”import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorageService { static const _storage = FlutterSecureStorage( aOptions: AndroidOptions( encryptedSharedPreferences: true, ), iOptions: IOSOptions( accessibility: KeychainAccessibility.first_unlock_this_device, ), );
// Sauvegarder des données sensibles static Future<void> storeToken(String token) async { await _storage.write(key: 'auth_token', value: token); }
static Future<void> storeCredentials(String username, String password) async { await _storage.write(key: 'username', value: username); await _storage.write(key: 'password', value: password); }
// Lire des données static Future<String?> getToken() async { return await _storage.read(key: 'auth_token'); }
static Future<Map<String, String?>>getCredentials() async { final username = await _storage.read(key: 'username'); final password = await _storage.read(key: 'password'); return {'username': username, 'password': password}; }
// Supprimer des données static Future<void> deleteToken() async { await _storage.delete(key: 'auth_token'); }
static Future<void> deleteAll() async { await _storage.deleteAll(); }
// Vérifier l'existence d'une clé static Future<bool> hasToken() async { return await _storage.containsKey(key: 'auth_token'); }
// Lister toutes les clés static Future<Map<String, String>> getAllData() async { return await _storage.readAll(); }}Options de Configuration Avancées
Section titled “Options de Configuration Avancées”Android Options
Section titled “Android Options”const AndroidOptions androidOptions = AndroidOptions( encryptedSharedPreferences: true, resetOnError: true, sharedPreferencesName: 'secure_preferences', preferencesKeyPrefix: 'flutter_secure_storage_',);iOS Options
Section titled “iOS Options”const IOSOptions iosOptions = IOSOptions( accessibility: KeychainAccessibility.first_unlock_this_device, groupId: 'group.com.example.app', synchronizable: false, accountName: 'FlutterSecureStorage',);Niveaux d’Accessibilité iOS
Section titled “Niveaux d’Accessibilité iOS”first_unlock_this_device: Accessible après le premier déverrouillageunlocked_this_device: Accessible seulement quand déverrouilléfirst_unlock: Accessible après le premier déverrouillage (synchronisable)unlocked: Accessible seulement quand déverrouillé (synchronisable)
Service d’Authentification Sécurisé
Section titled “Service d’Authentification Sécurisé”class AuthStorageService { static const _storage = FlutterSecureStorage( aOptions: AndroidOptions( encryptedSharedPreferences: true, ), iOptions: IOSOptions( accessibility: KeychainAccessibility.first_unlock_this_device, ), );
static const String _accessTokenKey = 'access_token'; static const String _refreshTokenKey = 'refresh_token'; static const String _userIdKey = 'user_id';
// Sauvegarder les tokens d'authentification static Future<void> saveAuthTokens({ required String accessToken, required String refreshToken, required String userId, }) async { await Future.wait([ _storage.write(key: _accessTokenKey, value: accessToken), _storage.write(key: _refreshTokenKey, value: refreshToken), _storage.write(key: _userIdKey, value: userId), ]); }
// Récupérer les tokens static Future<Map<String, String?>> getAuthTokens() async { final results = await Future.wait([ _storage.read(key: _accessTokenKey), _storage.read(key: _refreshTokenKey), _storage.read(key: _userIdKey), ]);
return { 'accessToken': results[0], 'refreshToken': results[1], 'userId': results[2], }; }
// Vérifier si l'utilisateur est connecté static Future<bool> isLoggedIn() async { final accessToken = await _storage.read(key: _accessTokenKey); return accessToken != null && accessToken.isNotEmpty; }
// Déconnexion - supprimer tous les tokens static Future<void> logout() async { await Future.wait([ _storage.delete(key: _accessTokenKey), _storage.delete(key: _refreshTokenKey), _storage.delete(key: _userIdKey), ]); }
// Mettre à jour seulement l'access token static Future<void> updateAccessToken(String newAccessToken) async { await _storage.write(key: _accessTokenKey, value: newAccessToken); }}Gestion d’Erreurs
Section titled “Gestion d’Erreurs”class SecureStorageWrapper { static const _storage = FlutterSecureStorage();
static Future<String?> readSafely(String key) async { try { return await _storage.read(key: key); } catch (e) { print('Erreur lors de la lecture de $key: $e'); return null; } }
static Future<bool> writeSafely(String key, String value) async { try { await _storage.write(key: key, value: value); return true; } catch (e) { print('Erreur lors de l\'écriture de $key: $e'); return false; } }
static Future<bool> deleteSafely(String key) async { try { await _storage.delete(key: key); return true; } catch (e) { print('Erreur lors de la suppression de $key: $e'); return false; } }}Bonnes Pratiques de Sécurité
Section titled “Bonnes Pratiques de Sécurité”- Données sensibles uniquement : Ne stocker que les données réellement sensibles
- Rotation des tokens : Implémenter un système de rotation des tokens
- Expiration : Gérer l’expiration des données stockées
- Validation : Valider les données avant le stockage
- Nettoyage : Supprimer les données lors de la déconnexion
- Gestion d’erreurs : Toujours gérer les exceptions
- Tests : Tester sur différents appareils et versions d’OS
Cas d’Usage Recommandés
Section titled “Cas d’Usage Recommandés”- Tokens d’authentification : JWT, OAuth tokens, API keys
- Identifiants de connexion : Mots de passe, biométrie
- Clés de chiffrement : Clés AES, certificats
- Données personnelles sensibles : Numéros de sécurité sociale, informations bancaires
- Configuration sensible : URLs privées, secrets d’application
Limitations et Considérations
Section titled “Limitations et Considérations”- Performance : Plus lent que SharedPreferences
- Taille : Limité à de petites quantités de données
- Compatibilité : Vérifier les versions d’Android/iOS supportées
- Backup : Les données peuvent être perdues lors de restaurations système