如何在Flutter的SQLite数据库中实现用户专属数据隔离?
解决方案:通过用户ID字段实现SQLite数据隔离
要实现同一设备不同用户的数据隔离,核心是给每条数据绑定当前登录用户的Firebase UID,所有数据库操作都基于这个UID做过滤。以下是具体修改步骤:
1. 更新数据模型与表字段
首先在你的CalcResult模型中添加userId字段,同时更新对应的字段常量和序列化方法:
// 修改CalcResult模型 class CalcResult { final int? id; final String userId; // 新增用户ID字段 // 保留原有其他字段 CalcResult({ this.id, required this.userId, // 原有字段的构造参数 }); // 更新copy方法,包含userId CalcResult copy({ int? id, String? userId, // 原有字段的copy参数 }) { return CalcResult( id: id ?? this.id, userId: userId ?? this.userId, // 原有字段的赋值 ); } // 更新toJson方法 Map<String, dynamic> toJson() => { CalcResultFields.id: id, CalcResultFields.userId: userId, // 原有字段的序列化 }; // 更新fromJson方法 static CalcResult fromJson(Map<String, dynamic> json) => CalcResult( id: json[CalcResultFields.id] as int?, userId: json[CalcResultFields.userId] as String, // 原有字段的反序列化 ); } // 更新字段常量类 class CalcResultFields { static final List<String> calcValues = [id, userId, /* 原有字段 */]; static const String id = '_id'; static const String userId = 'user_id'; // 新增字段常量 // 原有字段常量 }
2. 更新数据库表结构(创建与升级)
修改数据库的_create和_update方法,添加user_id列:
// 修改_create方法,创建表时加入user_id字段 Future<void> _create(Database db) async { await db.execute(''' CREATE TABLE $calcResults ( ${CalcResultFields.id} INTEGER PRIMARY KEY AUTOINCREMENT, ${CalcResultFields.userId} TEXT NOT NULL, -- 新增用户ID列,添加非空约束 -- 原有字段定义 ) '''); } // 修改_update方法,处理表结构升级(版本从11升至12) Future<void> _update(Database db, int oldVersion, int newVersion) async { if (oldVersion < 12) { // 给现有表添加user_id列,默认空字符串(可根据实际需求调整) await db.execute('ALTER TABLE $calcResults ADD COLUMN ${CalcResultFields.userId} TEXT NOT NULL DEFAULT ""'); // 可选:给存量数据补全用户ID(如果是已上线应用,需谨慎处理) } // 原有升级逻辑 } // 更新数据库版本号 Future<Database> _initDB(String filePath) async { final path = await getDatabasesPath(); final dbPath = join(path, filePath); return await openDatabase(dbPath, version: 12, // 版本号+1 onCreate: _create, onUpgrade: _update); }
3. 创建数据时自动绑定用户ID
在创建数据的方法中,获取当前登录用户的Firebase UID并注入到数据对象:
import 'package:firebase_auth/firebase_auth.dart'; Future<CalcResult> create(CalcResult calcResult) async { final db = await instance.database; final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { throw Exception('用户未登录'); } // 将用户ID绑定到待创建的数据 final userBoundResult = calcResult.copy(userId: currentUser.uid); final id = await db.insert(calcResults, userBoundResult.toJson()); return userBoundResult.copy(id: id); }
4. 读取数据时过滤当前用户ID
修改读取单条和所有数据的方法,添加用户ID的过滤条件:
读取单条数据:
Future<CalcResult> readNote(int id) async { final db = await instance.database; final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { throw Exception('用户未登录'); } final maps = await db.query( calcResults, columns: CalcResultFields.calcValues, where: '${CalcResultFields.id} = ? AND ${CalcResultFields.userId} = ?', whereArgs: [id, currentUser.uid], ); if (maps.isNotEmpty) { return CalcResult.fromJson(maps.first); } else { throw Exception('ID $id不存在或不属于当前用户'); } }
读取所有数据:
Future<List<CalcResult>> readAllNotes() async { final db = await instance.database; final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { throw Exception('用户未登录'); } final orderBy = '${CalcResultFields.toDate} DESC, ${CalcResultFields.toTime} DESC'; final result = await db.query( calcResults, orderBy: orderBy, where: '${CalcResultFields.userId} = ?', whereArgs: [currentUser.uid], ); return result.map((json) => CalcResult.fromJson(json)).toList(); }
可选优化:用户登出时重置数据库实例
在用户登出后重置数据库实例,避免后续操作出现异常:
// 在DatabaseClientCalculations类中添加重置方法 Future<void> resetDatabase() async { if (_database != null) { await _database!.close(); _database = null; } } // 登出时调用 await FirebaseAuth.instance.signOut(); await DatabaseClientCalculations.instance.resetDatabase();
修改完成后,每条数据都会与对应的用户UID绑定,不同用户登录后仅能访问自己的数据,实现了数据隔离。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

