diff --git a/lib/providers/sync_providers.dart b/lib/providers/sync_providers.dart index 7950d531c..d48a8d5dc 100644 --- a/lib/providers/sync_providers.dart +++ b/lib/providers/sync_providers.dart @@ -141,17 +141,20 @@ final s3ConfigProvider = FutureProvider((ref) async { }); final authServiceProvider = FutureProvider((ref) async { - final activeAsync = ref.watch(activeCloudConfigProvider); - if (!activeAsync.hasValue) { - return NoopAuthService(); - } - - final config = activeAsync.value!; + final config = await ref.watch(activeCloudConfigProvider.future); if (!config.valid || config.type == CloudBackendType.local) { return NoopAuthService(); } try { + // BeeCount Cloud 必须复用同步引擎持有的唯一 provider/auth 实例。 + // 多个实例虽然共用 SharedPreferences,却各自缓存 session;这会让 2FA + // 登录成功后同步实例仍停留在未登录状态。 + if (config.type == CloudBackendType.beecountCloud) { + final provider = await ref.watch(beecountCloudProviderInstance.future); + return provider?.auth ?? NoopAuthService(); + } + final services = await createCloudServices(config); if (services.auth != null) { return services.auth!; @@ -488,10 +491,7 @@ final syncServiceProvider = Provider((ref) { /// 用于 SyncEngine 和其他需要直接访问 BeeCount Cloud API 的场景 final beecountCloudProviderInstance = FutureProvider((ref) async { - final configAsync = ref.watch(activeCloudConfigProvider); - if (!configAsync.hasValue) return null; - - final config = configAsync.value!; + final config = await ref.watch(activeCloudConfigProvider.future); if (!config.valid || config.type != CloudBackendType.beecountCloud) { return null; } diff --git a/test/providers/beecount_cloud_auth_provider_test.dart b/test/providers/beecount_cloud_auth_provider_test.dart new file mode 100644 index 000000000..3a43ea036 --- /dev/null +++ b/test/providers/beecount_cloud_auth_provider_test.dart @@ -0,0 +1,36 @@ +import 'package:flutter_cloud_sync/flutter_cloud_sync.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:beecount/providers/sync_providers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + SharedPreferences.setMockInitialValues({}); + }); + + test('BeeCount Cloud UI auth and SyncEngine share one auth instance', + () async { + const config = CloudServiceConfig( + type: CloudBackendType.beecountCloud, + name: 'BeeCount Cloud', + beecountCloudBaseUrl: 'https://cloud.example.com', + beecountCloudApiPrefix: '/api/v1', + ); + final container = ProviderContainer( + overrides: [ + activeCloudConfigProvider.overrideWith((ref) async => config), + ], + ); + addTearDown(container.dispose); + + final provider = await container.read(beecountCloudProviderInstance.future); + final auth = await container.read(authServiceProvider.future); + + expect(provider, isNotNull); + expect(identical(auth, provider!.auth), isTrue); + }); +}