Flutter中用SharedPreferences保存用户角色并按角色跳转页面
Flutter多角色登录状态持久化实现方案
1. 扩展SharedPreferences工具类(preference_helper.dart)
在原有登录状态存储基础上,新增用户角色的存储与读取方法:
import 'package:shared_preferences/shared_preferences.dart'; class PreferencesHelper { final Future<SharedPreferences> sharedPreferences; const PreferencesHelper({required this.sharedPreferences}); static const String loginKey = 'LOGIN'; static const String roleKey = 'USER_ROLE'; // 新增角色存储标识 // 保存登录状态 void setIsLogin(bool value) async { final prefs = await sharedPreferences; prefs.setBool(loginKey, value); } // 获取登录状态 Future<bool> get isLogin async { final prefs = await sharedPreferences; return prefs.getBool(loginKey) ?? false; } // 新增:保存用户角色 void setUserRole(String role) async { final prefs = await sharedPreferences; prefs.setString(roleKey, role); } // 新增:获取用户角色 Future<String?> get userRole async { final prefs = await sharedPreferences; return prefs.getString(roleKey); } // 新增:清除登录状态与角色(退出登录时调用) void clearAuthData() async { final prefs = await sharedPreferences; prefs.remove(loginKey); prefs.remove(roleKey); } }
2. 更新状态通知器(preference_notifier.dart)
同步扩展状态管理逻辑,增加角色状态的监听与更新:
import 'package:flutter/material.dart'; import 'preference_helper.dart'; class PreferencesNotifier extends ChangeNotifier { PreferencesHelper preferencesHelper; PreferencesNotifier({required this.preferencesHelper}) { _getAuthData(); // 替换原单一获取登录状态的方法,同时获取角色 } bool _isLogin = false; bool get isLogin => _isLogin; String? _userRole; String? get userRole => _userRole; // 新增:同时获取登录状态和角色 void _getAuthData() async { _isLogin = await preferencesHelper.isLogin; _userRole = await preferencesHelper.userRole; notifyListeners(); debugPrint('登录状态: $_isLogin, 用户角色: $_userRole'); } // 更新:设置登录状态时可同步保存角色 void setAuthState(bool isLogin, [String? role]) async { await preferencesHelper.setIsLogin(isLogin); if (role != null) { await preferencesHelper.setUserRole(role); } _getAuthData(); // 重新拉取数据并更新状态 } // 新增:退出登录时清除存储数据 void logout() async { await preferencesHelper.clearAuthData(); _getAuthData(); } }
3. 修改登录页面逻辑
登录成功后从Firestore获取角色,保存到SharedPreferences并直接跳转对应页面:
MaterialButton( color: primaryColor, textTheme: ButtonTextTheme.primary, height: 40, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), onPressed: () async { setState(() { _isLoading = true; }); try { final navigator = Navigator.of(context); final email = _emailController.text; final password = _passwordController.text; // 完成Firebase登录验证 await _auth.signInWithEmailAndPassword( email: email, password: password, ); User? user = FirebaseAuth.instance.currentUser; if (user != null) { // 从Firestore获取用户角色 DocumentSnapshot userDoc = await FirebaseFirestore.instance .collection('users') .doc(user.uid) .get(); if (userDoc.exists) { String role = userDoc.get('role'); // 保存登录状态和角色到本地 value.setAuthState(true, role); // 根据角色跳转对应首页 if (role == "user") { navigator.pushReplacementNamed(UserHomePage.routeName); } else { navigator.pushReplacementNamed(AdminHomePage.routeName); } } else { debugPrint('用户数据不存在'); } } } catch (err) { final snackBar = SnackBar(content: Text(err.toString())); ScaffoldMessenger.of(context).showSnackBar(snackBar); } finally { setState(() { _isLoading = false; }); } }, child: const Text('Login'), ),
注意:移除原登录逻辑中的route()和navigator.pushReplacementNamed(HomePage.routeName),避免重复跳转冲突。
4. 调整APP启动路由(main.dart)
启动时直接根据本地存储的角色跳转对应页面:
// 初始化PreferencesHelper final preferencesHelper = PreferencesHelper( sharedPreferences: SharedPreferences.getInstance(), ); // 获取本地存储的登录状态和角色 bool isLoggedIn = await preferencesHelper.isLogin; String? userRole = await preferencesHelper.userRole; // 确定初始路由 String initialRoute = LoginPage.routeName; if (isLoggedIn) { initialRoute = userRole == "user" ? UserHomePage.routeName : AdminHomePage.routeName; } runApp( MyApp( pageRouteName: initialRoute, ), );
5. 退出登录逻辑补充(可选)
在退出按钮中调用清除方法,同步本地存储和Firebase状态:
TextButton( onPressed: () async { await FirebaseAuth.instance.signOut(); Provider.of<PreferencesNotifier>(context, listen: false).logout(); Navigator.pushReplacementNamed(context, LoginPage.routeName); }, child: const Text('退出登录'), )
内容的提问来源于stack exchange,提问作者Akhmad Kurniawan
相关产品推荐
相关产品推荐

