auth_repository.dart 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import 'package:flutter_riverpod/flutter_riverpod.dart';
  2. import 'package:flutter_secure_storage/flutter_secure_storage.dart';
  3. import '../../core/network/dio_client.dart';
  4. import '../services/auth_service.dart';
  5. export '../services/auth_service.dart'
  6. show CheckAccountForRegisterResult, LoginResult;
  7. const _kToken = 'auth_token';
  8. const _kUid = 'auth_uid';
  9. const _kEmail = 'auth_email';
  10. /// 认证仓库:持久化 Token,对外暴露登录状态
  11. class AuthRepository {
  12. const AuthRepository(this._service, this._storage);
  13. final AuthService _service;
  14. final FlutterSecureStorage _storage;
  15. // ── Token 读写 ──────────────────────────────────────────
  16. Future<String?> getToken() => _storage.read(key: _kToken);
  17. Future<bool> get isLoggedIn async {
  18. final token = await _storage.read(key: _kToken);
  19. return token != null && token.isNotEmpty;
  20. }
  21. Future<void> _saveSession(LoginResult result) async {
  22. await Future.wait([
  23. _storage.write(key: _kToken, value: result.token),
  24. if (result.uid != null) _storage.write(key: _kUid, value: result.uid!),
  25. if (result.email != null)
  26. _storage.write(key: _kEmail, value: result.email!),
  27. ]);
  28. updateCachedToken(result.token); // 同步更新内存缓存
  29. }
  30. /// 清除本地登录态(session 过期时直接调用,不请求接口)
  31. Future<void> clearSession() => _clearSession();
  32. Future<void> _clearSession() async {
  33. updateCachedToken(null); // 立即清除内存缓存,防止并发请求带旧 token
  34. await Future.wait([
  35. _storage.delete(key: _kToken),
  36. _storage.delete(key: _kUid),
  37. _storage.delete(key: _kEmail),
  38. ]);
  39. }
  40. // ── 登录流程 ────────────────────────────────────────────
  41. /// 登录发码前校验密码
  42. Future<void> checkLoginPassword({
  43. required String email,
  44. required String password,
  45. }) =>
  46. _service.checkLoginPassword(username: email, password: password);
  47. /// 注册发码前校验账号是否已存在
  48. Future<CheckAccountForRegisterResult> checkAccountForRegister(
  49. String email,
  50. ) =>
  51. _service.checkAccountForRegister(email);
  52. /// 发送登录邮箱验证码
  53. Future<void> sendLoginCode(String email) =>
  54. _service.sendLoginEmailCode(email);
  55. /// 密码+验证码登录
  56. Future<LoginResult> loginWithPassword({
  57. required String email,
  58. required String password,
  59. required String code,
  60. String vtype = '2',
  61. }) async {
  62. final result = await _service.loginWithPassword(
  63. email: email,
  64. password: password,
  65. code: code,
  66. vtype: vtype,
  67. );
  68. await _saveSession(result);
  69. return result;
  70. }
  71. // ── 注册流程 ────────────────────────────────────────────
  72. /// 发送注册邮箱验证码
  73. Future<void> sendRegisterCode(String email) =>
  74. _service.sendRegisterEmailCode(email);
  75. /// 邮箱注册
  76. Future<void> registerWithEmail({
  77. required String email,
  78. required String password,
  79. required String code,
  80. String? inviteCode,
  81. }) async {
  82. await _service.registerWithEmail(
  83. email: email,
  84. password: password,
  85. code: code,
  86. inviteCode: inviteCode,
  87. );
  88. }
  89. // ── 忘记密码流程 ────────────────────────────────────────
  90. /// 发送重置密码邮箱验证码
  91. Future<void> sendResetCode(String email) =>
  92. _service.sendResetEmailCode(email);
  93. /// 重置密码
  94. Future<void> resetPassword({
  95. required String email,
  96. required String password,
  97. required String code,
  98. }) async {
  99. await _service.resetPassword(
  100. email: email,
  101. password: password,
  102. code: code,
  103. );
  104. }
  105. // ── 退出登录 ────────────────────────────────────────────
  106. Future<void> logout() async {
  107. // 先清除本地 token,防止 logout 接口返回 4000 时 Dio 拦截器误触发过期弹窗
  108. await _clearSession();
  109. try {
  110. await _service.logout();
  111. } catch (_) {
  112. // 接口失败不影响本地登出(token 可能已过期)
  113. }
  114. }
  115. /// 读取登录时保存在本地的 uid(登录时必定写入,可作可靠兜底)
  116. Future<String?> getSavedUid() => _storage.read(key: _kUid);
  117. // ── 获取用户信息 ────────────────────────────────────────
  118. Future<Map<String, dynamic>> getMyInfo() => _service.getMyInfo();
  119. }
  120. // ── Providers ──────────────────────────────────────────────
  121. final authServiceProvider = Provider<AuthService>((ref) {
  122. final dio = ref.watch(dioClientProvider);
  123. return AuthService(dio);
  124. });
  125. final authRepositoryProvider = Provider<AuthRepository>((ref) {
  126. final service = ref.watch(authServiceProvider);
  127. final storage = ref.watch(secureStorageProvider);
  128. return AuthRepository(service, storage);
  129. });