auth_store.dart 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import 'package:chicken_farm/apis/index.dart';
  2. import 'package:chicken_farm/core/config/app_config.dart';
  3. import 'package:chicken_farm/core/services/connectivity_service.dart';
  4. import 'package:chicken_farm/core/services/navigation_service.dart';
  5. import 'package:chicken_farm/core/utils/jwt_token.dart';
  6. import 'package:chicken_farm/core/utils/logger.dart';
  7. import 'package:chicken_farm/modes/auth/login_model.dart';
  8. import 'package:chicken_farm/modes/user/user_model.dart';
  9. import 'package:chicken_farm/routes/app_routes.dart';
  10. import 'package:flutter_riverpod/flutter_riverpod.dart';
  11. import 'package:go_router/go_router.dart';
  12. /// 认证状态枚举
  13. enum AuthState { authenticated, unauthenticated, loading }
  14. /// 用户认证信息状态
  15. class AuthInfo {
  16. final AuthState state;
  17. final String? token;
  18. final UserModel? user;
  19. final List<String>? permissions;
  20. final List<String>? roles;
  21. AuthInfo({
  22. required this.state,
  23. this.token,
  24. this.user,
  25. this.permissions,
  26. this.roles,
  27. });
  28. /// 创建已认证状态
  29. AuthInfo.authenticated({
  30. required String token,
  31. required UserModel user,
  32. List<String>? permissions,
  33. List<String>? roles,
  34. }) : this(
  35. state: AuthState.authenticated,
  36. token: token,
  37. user: user,
  38. permissions: permissions,
  39. roles: roles,
  40. );
  41. /// 创建未认证状态
  42. AuthInfo.unauthenticated()
  43. : this(
  44. state: AuthState.unauthenticated,
  45. token: null,
  46. user: null,
  47. permissions: const [],
  48. roles: const [],
  49. );
  50. /// 创建加载状态
  51. AuthInfo.loading()
  52. : this(
  53. state: AuthState.loading,
  54. token: null,
  55. user: null,
  56. permissions: const [],
  57. roles: const [],
  58. );
  59. /// 复制对象并更新部分字段
  60. AuthInfo copyWith({
  61. AuthState? state,
  62. String? token,
  63. UserModel? user,
  64. List<String>? permissions,
  65. List<String>? roles,
  66. }) {
  67. return AuthInfo(
  68. state: state ?? this.state,
  69. token: token ?? this.token,
  70. user: user ?? this.user,
  71. permissions: permissions ?? this.permissions,
  72. roles: roles ?? this.roles,
  73. );
  74. }
  75. }
  76. class AuthStore extends StateNotifier<AuthInfo> {
  77. AuthStore() : super(AuthInfo.unauthenticated()) {
  78. _init();
  79. }
  80. /// 初始化认证状态
  81. Future<void> _init() async {
  82. state = AuthInfo.loading();
  83. try {
  84. final token = await JwtToken.getToken();
  85. if (token != null) {
  86. // 检查网络连接状态
  87. final container = ProviderContainer();
  88. final isConnected = await container.read(isConnectedProvider.future);
  89. if (isConnected) {
  90. // 有网络连接,强制获取最新用户信息
  91. try {
  92. final userInfo = await apis.loginApi.getInfo();
  93. if (userInfo == null) {
  94. throw Exception('用户信息获取失败');
  95. }
  96. // 保存用户信息到本地存储,供离线时使用
  97. await JwtToken.saveUserInfo(userInfo);
  98. state = AuthInfo.authenticated(
  99. token: token,
  100. user: userInfo.user!,
  101. permissions: userInfo.permissions,
  102. roles: userInfo.roles,
  103. );
  104. logger.i('在线模式下已登录 state: $state');
  105. } catch (e) {
  106. // 网络连接但是获取用户信息失败,可能是token过期
  107. logger.e('在线模式下获取用户信息失败: $e');
  108. await JwtToken.clear();
  109. state = AuthInfo.unauthenticated();
  110. }
  111. } else {
  112. // 无网络连接,使用离线模式
  113. try {
  114. // 尝试从本地存储获取上次登录的用户信息
  115. final cachedUserInfo = await JwtToken.getUserInfo();
  116. if (cachedUserInfo != null && cachedUserInfo.user != null) {
  117. state = AuthInfo.authenticated(
  118. token: token,
  119. user: cachedUserInfo.user!,
  120. permissions: cachedUserInfo.permissions ?? [],
  121. roles: cachedUserInfo.roles ?? [],
  122. );
  123. logger.i('离线模式下使用缓存用户信息: $state');
  124. } else {
  125. // 没有缓存的用户信息,不能进行离线认证
  126. logger.w('离线模式下无缓存用户信息,无法进行离线认证');
  127. state = AuthInfo.unauthenticated();
  128. }
  129. } catch (e) {
  130. logger.e('离线模式初始化失败: $e');
  131. state = AuthInfo.unauthenticated();
  132. }
  133. }
  134. } else {
  135. state = AuthInfo.unauthenticated();
  136. }
  137. } catch (e) {
  138. logger.e('认证初始化失败: $e');
  139. state = AuthInfo.unauthenticated();
  140. }
  141. }
  142. /// 登录操作
  143. Future<void> login(LoginModel loginModel) async {
  144. state = AuthInfo.loading();
  145. try {
  146. loginModel.clientId = AppConfig.clientId;
  147. final authResult = await apis.loginApi.login(loginModel);
  148. final token = authResult.accessToken;
  149. await JwtToken.setToken(token, authResult.refreshToken);
  150. // 获取用户信息
  151. final userInfo = await apis.loginApi.getInfo();
  152. if (userInfo == null) {
  153. throw Exception('用户信息获取失败');
  154. }
  155. // 保存用户信息到本地存储,供离线时使用
  156. await JwtToken.saveUserInfo(userInfo);
  157. state = AuthInfo.authenticated(
  158. token: token,
  159. user: userInfo.user!,
  160. permissions: userInfo.permissions,
  161. roles: userInfo.roles,
  162. );
  163. logger.i('登录成功 state: $state');
  164. } catch (e) {
  165. await JwtToken.clear();
  166. state = AuthInfo.unauthenticated();
  167. }
  168. }
  169. /// 登出操作
  170. Future<void> logout() async {
  171. try {
  172. await apis.loginApi.logout();
  173. } catch (e) {
  174. // 即使API调用失败也要清除本地状态
  175. logger.e('Logout API call failed: $e');
  176. } finally {
  177. await JwtToken.clear();
  178. state = AuthInfo.unauthenticated();
  179. if (NavigationService.navigatorKey.currentState != null &&
  180. NavigationService.navigatorKey.currentContext != null) {
  181. NavigationService.navigatorKey.currentContext!.goNamed(
  182. AppRouteNames.login,
  183. );
  184. }
  185. }
  186. }
  187. /// 刷新token
  188. Future<void> refreshToken() async {
  189. try {
  190. final refreshToken = await JwtToken.getRefreshToken();
  191. if (refreshToken != null) {
  192. final authResult = await apis.loginApi.refreshToken(refreshToken);
  193. final newToken = authResult.accessToken;
  194. await JwtToken.setToken(newToken, authResult.refreshToken);
  195. state = state.copyWith(token: newToken);
  196. }
  197. } catch (e) {
  198. // 刷新失败则登出
  199. await logout();
  200. rethrow;
  201. }
  202. }
  203. /// 重新获取用户信息
  204. Future<void> getUserInfo() async {
  205. try {
  206. final userInfo = await apis.loginApi.getInfo();
  207. if (userInfo == null) {
  208. throw Exception('用户信息获取失败');
  209. }
  210. // 更新本地存储的用户信息
  211. await JwtToken.saveUserInfo(userInfo);
  212. state = state.copyWith(
  213. user: userInfo.user,
  214. permissions: userInfo.permissions,
  215. roles: userInfo.roles,
  216. );
  217. } catch (e) {
  218. rethrow;
  219. }
  220. }
  221. /// 检查是否有特定权限
  222. bool hasPermission(String permission) {
  223. return state.permissions?.contains(permission) ?? false;
  224. }
  225. /// 检查是否有特定角色
  226. bool hasRole(String role) {
  227. return state.roles?.contains(role) ?? false;
  228. }
  229. /// 是否是超级管理员
  230. bool isSuperAdmin() {
  231. if (state.user == null) return false;
  232. return state.user!.userName == "admin" ||
  233. (state.roles?.contains("super_admin") ?? false);
  234. }
  235. }
  236. // 添加 Provider 实例
  237. final authStoreProvider = StateNotifierProvider<AuthStore, AuthInfo>(
  238. (ref) => AuthStore(),
  239. );