auth_store.dart 8.5 KB

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