如何在Flutter应用中通过Firebase实现APP内邮箱OTP改密码?是否免费?
Firebase 邮箱验证+APP内改密方案(Flutter)
1. 是否支持该功能?
Firebase本身没有直接提供“邮箱OTP验证码验证后改密”的原生流程,但可以通过结合邮箱链接登录验证和密码修改API实现完全在APP内完成改密的需求——本质是用邮箱链接完成用户身份验证(替代OTP验证码的作用),验证通过后直接在APP内调用接口修改密码。
2. 具体实现步骤(Flutter)
步骤1:发送邮箱验证链接
用户输入注册邮箱后,调用Firebase的sendSignInLinkToEmail方法,配置handleCodeInApp: true让链接跳转回APP,同时设置对应的deep link和平台参数:
import 'package:firebase_auth/firebase_auth.dart'; import 'package:shared_preferences/shared_preferences.dart'; Future<void> sendResetLink(String userEmail) async { final actionCodeSettings = ActionCodeSettings( url: 'https://yourapp.page.link/reset', // 你的APP专属deep link handleCodeInApp: true, iOSBundleId: 'com.yourapp.ios', // iOS包名 androidPackageName: 'com.yourapp.android', // Android包名 androidInstallApp: true, androidMinimumVersion: '12', ); await FirebaseAuth.instance.sendSignInLinkToEmail( email: userEmail, actionCodeSettings: actionCodeSettings, ); // 临时保存邮箱到本地,后续验证需要 final prefs = await SharedPreferences.getInstance(); prefs.setString('reset_temp_email', userEmail); }
步骤2:处理APP内的验证链接
配置Firebase Dynamic Links接收跳转回APP的链接,验证链接有效性并完成身份验证:
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; void initDynamicLinks(BuildContext context) async { // 处理APP启动时的链接 final initialLink = await FirebaseDynamicLinks.instance.getInitialLink(); if (initialLink != null) { _handleResetLink(initialLink.link, context); } // 监听后台唤醒的链接 FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) { _handleResetLink(dynamicLinkData.link, context); }); } Future<void> _handleResetLink(Uri deepLink, BuildContext context) async { if (FirebaseAuth.instance.isSignInWithEmailLink(deepLink.toString())) { final prefs = await SharedPreferences.getInstance(); final email = prefs.getString('reset_temp_email'); if (email != null) { try { // 完成身份验证(无需密码,通过链接确认用户身份) await FirebaseAuth.instance.signInWithEmailLink( email: email, emailLink: deepLink.toString(), ); // 验证成功,跳转到APP内的改密页面 Navigator.push( context, MaterialPageRoute(builder: (_) => const ResetPasswordPage()), ); } catch (e) { // 处理验证失败(如链接过期、邮箱不匹配等) print('验证失败: $e'); } } } }
步骤3:APP内修改密码
在改密页面,调用Firebase的updatePassword方法完成密码修改:
import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; class ResetPasswordPage extends StatefulWidget { const ResetPasswordPage({super.key}); @override State<ResetPasswordPage> createState() => _ResetPasswordPageState(); } class _ResetPasswordPageState extends State<ResetPasswordPage> { final _newPasswordController = TextEditingController(); final _auth = FirebaseAuth.instance; Future<void> _resetPassword() async { final user = _auth.currentUser; final newPassword = _newPasswordController.text.trim(); if (user != null && newPassword.isNotEmpty) { try { await user.updatePassword(newPassword); // 改密成功,提示用户并退出登录 await _auth.signOut(); Navigator.popUntil(context, (route) => route.isFirst); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('密码修改成功,请重新登录')), ); } catch (e) { // 处理错误(如密码强度不足、用户会话过期等) ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('修改失败: ${e.toString()}')), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('修改密码')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextField( controller: _newPasswordController, obscureText: true, decoration: const InputDecoration(labelText: '新密码'), ), const SizedBox(height: 20), ElevatedButton( onPressed: _resetPassword, child: const Text('确认修改'), ), ], ), ), ); } }
3. 免费计划是否包含该功能?
是的,Firebase免费计划(Spark计划)完全支持上述功能:
- 邮箱验证链接的发送和验证属于**身份验证(Authentication)**服务的免费内容,每月免费额度包含10,000条验证邮件发送;
- 用户密码修改API调用也属于Authentication的基础功能,无额外收费,只要不超过免费计划的其他限制(如每月活跃用户数等)即可正常使用。
内容的提问来源于stack exchange,提问作者Mikelenjilo
相关产品推荐
相关产品推荐

