Flutter登录后会话存储、登录校验及自定义仪表盘实现咨询
解决方案与实现思路
一、登录后获取用户个性化数据
1. 后端接口调整
PHP登录验证接口在确认邮箱密码正确后,除返回登录成功状态,还需返回用户的个性化数据(如用户名、主题偏好、常用设置等)。示例PHP代码:
<?php // 验证邮箱密码逻辑(略) if ($valid) { // 从MySQL查询用户个性化数据 $userData = $db->query("SELECT username, theme, preferred_lang FROM users WHERE email = '$email'")->fetch_assoc(); // 返回JSON响应 echo json_encode([ 'status' => 'success', 'user' => $userData ]); } else { echo json_encode(['status' => 'error', 'msg' => '登录失败']); } ?>
2. Flutter端处理与本地存储
登录请求成功后,解析后端返回的用户数据,用shared_preferences(轻量键值存储)或Hive(本地数据库)保存到设备本地,仪表盘页面从本地读取数据渲染个性化内容。示例Flutter代码:
import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; // 登录请求方法 Future<void> login(String email, String password, BuildContext context) async { final response = await http.post( Uri.parse('你的PHP接口地址'), body: {'email': email, 'password': password}, ); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['status'] == 'success') { // 保存用户数据到本地 final prefs = await SharedPreferences.getInstance(); await prefs.setString('username', data['user']['username']); await prefs.setString('theme', data['user']['theme']); // 跳转到仪表盘 Navigator.pushReplacementNamed(context, '/dashboard'); } } } // 仪表盘页面读取数据 class DashboardPage extends StatefulWidget { @override State<DashboardPage> createState() => _DashboardPageState(); } class _DashboardPageState extends State<DashboardPage> { String? username; String? theme; @override void initState() { super.initState(); _loadUserData(); } Future<void> _loadUserData() async { final prefs = await SharedPreferences.getInstance(); setState(() { username = prefs.getString('username') ?? '默认用户'; theme = prefs.getString('theme') ?? 'light'; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('欢迎,$username')), body: Center(child: Text('当前主题:$theme')), ); } }
二、会话校验与登录状态维持
1. 基于JWT的无状态会话实现
后端(PHP)生成JWT
使用firebase/php-jwt库生成包含用户ID、过期时间的JWT,登录成功后随用户数据一起返回。示例代码:
<?php require 'vendor/autoload.php'; use Firebase\JWT\JWT; $secretKey = '你的自定义密钥(需保密)'; $payload = [ 'user_id' => $userData['id'], 'exp' => time() + 3600 // 令牌1小时后过期 ]; $jwt = JWT::encode($payload, $secretKey, 'HS256'); // 返回响应时带上JWT echo json_encode([ 'status' => 'success', 'user' => $userData, 'token' => $jwt ]); ?>
Flutter端存储JWT并携带请求
登录时保存JWT到本地,后续所有需要权限的接口请求都在请求头里带上Authorization: Bearer {token}。同时实现路由守卫,确保未登录用户无法进入仪表盘:
// 登录时保存JWT await prefs.setString('auth_token', data['token']); // 请求权限接口时携带JWT Future<void> fetchUserSettings() async { final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('auth_token'); final response = await http.get( Uri.parse('需要权限的用户设置接口'), headers: {'Authorization': 'Bearer $token'}, ); // 处理接口响应(略) } // 路由守卫(在MaterialApp的onGenerateRoute中实现) Route<dynamic>? generateRoute(RouteSettings settings) async { switch (settings.name) { case '/dashboard': final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('auth_token'); if (token != null) { return MaterialPageRoute(builder: (_) => DashboardPage()); } else { return MaterialPageRoute(builder: (_) => LoginPage()); } // 其他路由逻辑(略) default: return MaterialPageRoute(builder: (_) => LoginPage()); } }
2. 后端JWT校验
PHP接口收到请求时,校验请求头中的JWT有效性,无效则返回未授权状态:
<?php require 'vendor/autoload.php'; use Firebase\JWT\JWT; use Firebase\JWT\Key; $secretKey = '你的自定义密钥'; $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; if (str_starts_with($token, 'Bearer ')) { $token = substr($token, 7); try { $decoded = JWT::decode($token, new Key($secretKey, 'HS256')); // 校验通过,获取用户ID处理业务 $userId = $decoded->user_id; } catch (Exception $e) { http_response_code(401); echo json_encode(['status' => 'error', 'msg' => '未授权']); exit; } } else { http_response_code(401); echo json_encode(['status' => 'error', 'msg' => '缺少授权令牌']); exit; } // 后续业务逻辑(略) ?>
参考资源要点
- Flutter本地存储:
shared_preferences适合轻量键值对存储,Hive支持复杂对象或大量数据存储,可查看Flutter官方文档中本地存储章节的核心用法。 - JWT实现:PHP端依赖
firebase/php-jwt库,核心是生成包含用户标识和过期时间的令牌;Flutter端负责令牌的存储、携带与过期检测。 - 路由守卫:通过
onGenerateRoute或go_router等路由包实现页面权限控制,拦截未登录用户访问受保护页面。
内容的提问来源于stack exchange,提问作者Shawn Mulligan
相关产品推荐
相关产品推荐

