Flutter使用local_auth检测生物信息变更问题求助
解决local_auth检测生物信息变更的方案
local_auth包本身确实没有返回令牌类校验信息的机制,但可以借助系统密钥存储(iOS Keychain/Android Keystore)的特性间接实现生物信息变更检测——当用户修改生物信息后,绑定了生物认证权限的密钥会失效,通过校验密钥可用性即可判断生物信息是否变更。
核心思路
通过创建绑定生物认证的存储条目,每次生物认证通过后,尝试读取该条目:
- 若读取/解密成功,说明生物信息未变更
- 若读取失败或条目失效,说明生物信息已修改,需引导用户使用密码登录
具体实现步骤
1. 添加依赖
除local_auth外,引入flutter_secure_storage简化密钥存储操作:
dependencies: flutter: sdk: flutter local_auth: 2.1.7 flutter_secure_storage: ^9.0.0
2. 封装认证工具类
import 'dart:convert'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:local_auth/local_auth.dart'; class BiometricAuthManager { final LocalAuthentication _localAuth = LocalAuthentication(); final FlutterSecureStorage _storage = const FlutterSecureStorage(); final String _validationKey = 'biometric_validation_entry'; final String _fixedTestData = 'auth_validation_token'; // 检查设备是否支持生物认证 Future<bool> hasAvailableBiometrics() async { return await _localAuth.isDeviceSupported() && (await _localAuth.getAvailableBiometrics()).isNotEmpty; } // 首次绑定生物认证(登录成功后调用) Future<void> bindBiometricAuth() async { bool authenticated = await _localAuth.authenticate( localizedReason: '验证生物信息以完成绑定', options: const AuthenticationOptions(useErrorDialogs: true), ); if (!authenticated) return; // 存储绑定生物权限的验证数据 await _storage.write( key: _validationKey, value: base64Encode(utf8.encode(_fixedTestData)), ); } // 执行生物认证并检测信息变更 Future<AuthResult> authenticateAndCheck() async { try { // 第一步:执行生物认证 bool authPassed = await _localAuth.authenticate( localizedReason: '请验证身份以查看账户余额', options: const AuthenticationOptions(useErrorDialogs: true), ); if (!authPassed) { return AuthResult(success: false, message: '用户取消或生物验证失败'); } // 第二步:校验绑定的密钥是否有效 String? storedValue = await _storage.read(key: _validationKey); if (storedValue == null) { return AuthResult(success: false, message: '未绑定生物认证,请重新验证'); } try { // 尝试解码数据,生物信息变更后系统会阻止访问该条目,抛出异常 String decodedData = utf8.decode(base64Decode(storedValue)); if (decodedData != _fixedTestData) { await _storage.delete(key: _validationKey); return AuthResult(success: false, message: '生物信息已变更,请使用密码登录'); } } catch (_) { // 解码失败=密钥失效=生物信息已变更 await _storage.delete(key: _validationKey); return AuthResult(success: false, message: '生物信息已变更,请使用密码登录'); } return AuthResult(success: true); } on PlatformException catch (e) { if (e.code == 'notAvailable') { return AuthResult(success: false, message: '设备不支持生物认证'); } else if (e.code == 'notEnrolled') { return AuthResult(success: false, message: '未注册生物信息'); } else { return AuthResult(success: false, message: '认证错误:${e.message}'); } } } } // 认证结果模型 class AuthResult { final bool success; final String? message; AuthResult({required this.success, this.message}); }
3. 业务层调用示例
final authManager = BiometricAuthManager(); // 用户首次登录成功后,绑定生物认证 await authManager.bindBiometricAuth(); // 后续登录时调用 AuthResult result = await authManager.authenticateAndCheck(); if (result.success) { debugPrint('生物认证通过,信息未变更'); // 执行账户操作逻辑 } else { debugPrint(result.message); if (result.message?.contains('生物信息已变更') == true) { // 跳转至密码登录页面 } }
原理说明
- iOS: 绑定生物认证权限的Keychain条目,在用户修改面容ID/Touch ID后会被系统标记为不可访问,读取时直接抛出异常
- Android: 关联生物认证的Keystore密钥,在生物信息变更后会自动失效,无法完成解密操作
通过这种方式,就能间接实现生物信息变更的检测,弥补local_auth仅返回布尔值的局限性。
内容的提问来源于stack exchange,提问作者DennisCCC
相关产品推荐
相关产品推荐

