Flutter集成Firebase:整数值的存储与读取及自定义学号登录的存储方案技术咨询
针对你的两个问题,我来逐一给出实用的解决方案:
问题1:如何在Flutter中将整数值保存到Firebase,并读取已保存的该整数值?
Firebase提供了Cloud Firestore和Realtime Database两种常用数据库方案,我会分别给出实现代码:
Cloud Firestore 实现
保存整数值
先确保项目已集成cloud_firestore依赖,然后通过以下代码完成保存:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; Future<void> saveStudentId(int studentId) async { try { // 登录后通过Firebase Auth获取当前用户UID,作为文档ID确保唯一性 String userId = FirebaseAuth.instance.currentUser!.uid; await FirebaseFirestore.instance .collection('users') .doc(userId) .set({'studentId': studentId}, SetOptions(merge: true)); print("学号已成功保存"); } catch (e) { print("保存失败: $e"); // 可根据业务需求添加弹窗提示等错误处理逻辑 } }
读取整数值
Future<int?> getStudentId() async { try { String userId = FirebaseAuth.instance.currentUser!.uid; DocumentSnapshot userDoc = await FirebaseFirestore.instance .collection('users') .doc(userId) .get(); if (userDoc.exists) { // 注意将Firestore返回的动态类型转为int return userDoc['studentId'] as int?; } else { print("用户数据不存在"); return null; } } catch (e) { print("读取失败: $e"); return null; } }
Realtime Database 实现
如果使用Realtime Database,先集成firebase_database依赖:
保存整数值
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_auth/firebase_auth.dart'; Future<void> saveStudentIdToRealtimeDb(int studentId) async { try { String userId = FirebaseAuth.instance.currentUser!.uid; await FirebaseDatabase.instance .ref('users/$userId/studentId') .set(studentId); print("学号已成功保存"); } catch (e) { print("保存失败: $e"); } }
读取整数值
Future<int?> getStudentIdFromRealtimeDb() async { try { String userId = FirebaseAuth.instance.currentUser!.uid; DatabaseEvent event = await FirebaseDatabase.instance .ref('users/$userId/studentId') .once(); // 转换类型时需注意Realtime Database返回的动态类型 return event.snapshot.value as int?; } catch (e) { print("读取失败: $e"); return null; } }
问题2:使用学号(整数)和密码登录,Firebase Auth无此类表单,该整数值应存储在何处?
你说得没错,Firebase Auth默认没有直接的「学号+密码」登录方式,但我们可以通过Firebase Auth + 数据库存储自定义字段的组合方案实现,推荐两种实用思路:
方案1:结合Firebase Auth邮箱/密码登录 + Firestore存储学号
核心逻辑:用学号生成唯一占位邮箱(或让用户绑定真实邮箱),将学号作为用户自定义字段存入Firestore;登录时先通过学号找到对应邮箱,再用邮箱密码完成Auth登录。
注册流程示例
import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:bcrypt/bcrypt.dart'; // 用于密码哈希,避免明文存储 Future<UserCredential> registerWithStudentId(int studentId, String password) async { // 用学号生成唯一占位邮箱,避免重复注册 String placeholderEmail = "$studentId@yourschoolapp.com"; // 哈希密码后存储 String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt()); try { // 创建Firebase Auth用户 UserCredential userCred = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: placeholderEmail, password: password, ); // 将学号、哈希密码等信息存入Firestore,关联用户UID await FirebaseFirestore.instance .collection('users') .doc(userCred.user!.uid) .set({ 'studentId': studentId, 'email': placeholderEmail, 'hashedPassword': hashedPassword }); // 建议在Firebase控制台给studentId字段添加唯一索引,防止重复注册 return userCred; } catch (e) { print("注册失败: $e"); rethrow; } }
登录流程示例
Future<UserCredential> loginWithStudentId(int studentId, String password) async { try { // 通过学号在Firestore中查找对应用户 QuerySnapshot query = await FirebaseFirestore.instance .collection('users') .where('studentId', isEqualTo: studentId) .limit(1) .get(); if (query.docs.isEmpty) { throw Exception("未找到该学号对应的用户"); } // 获取用户的占位邮箱和哈希密码 String email = query.docs.first['email'] as String; String hashedPassword = query.docs.first['hashedPassword'] as String; // 验证密码是否匹配 if (!BCrypt.checkpw(password, hashedPassword)) { throw Exception("密码错误"); } // 用邮箱和密码完成Firebase Auth登录 return await FirebaseAuth.instance.signInWithEmailAndPassword( email: email, password: password, ); } catch (e) { print("登录失败: $e"); rethrow; } }
方案2:使用Firebase自定义令牌(适合无邮箱场景)
如果不想依赖邮箱,可以通过自定义令牌实现:后端(或Cloud Functions)验证学号和密码的合法性,生成自定义令牌后,前端用令牌完成Auth登录。
Cloud Functions 后端验证示例(Node.js)
const functions = require("firebase-functions"); const admin = require("firebase-admin"); const bcrypt = require("bcrypt"); admin.initializeApp(); exports.loginWithStudentId = functions.https.onCall(async (data) => { const { studentId, password } = data; // 查找学号对应的用户 const userQuery = await admin.firestore() .collection('users') .where('studentId', '==', studentId) .limit(1) .get(); if (userQuery.empty) { throw new functions.https.HttpsError("not-found", "用户不存在"); } const userDoc = userQuery.docs[0]; const userData = userDoc.data(); // 验证密码(注册时已存储哈希值) const isPasswordValid = await bcrypt.compare(password, userData.hashedPassword); if (!isPasswordValid) { throw new functions.https.HttpsError("unauthenticated", "密码错误"); } // 生成自定义令牌,以用户UID为标识 const customToken = await admin.auth().createCustomToken(userDoc.id); return { token: customToken }; });
Flutter 前端调用示例
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_functions/firebase_functions.dart'; Future<UserCredential> loginWithCustomToken(int studentId, String password) async { try { HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('loginWithStudentId'); final result = await callable.call({ 'studentId': studentId, 'password': password, }); String customToken = result.data['token']; return await FirebaseAuth.instance.signInWithCustomToken(customToken); } catch (e) { print("登录失败: $e"); rethrow; } }
关键注意事项
- 密码安全:绝对禁止明文存储密码,必须使用bcrypt等哈希算法处理后再存入数据库。
- 学号唯一性:在Firestore中给
studentId字段配置唯一索引,防止同一学号重复注册。
内容的提问来源于stack exchange,提问作者ckot
相关产品推荐
相关产品推荐

