如何通过Firebase云函数向大量用户发送无密码登录链接
针对一次性批量发送无密码登录链接的解决方案
因为Firebase Admin SDK确实不支持sendSignInLinkToEmail(),给你两个无需修改现有应用的简便方案,都是本地脚本就能搞定的一次性操作:
方案一:用Admin SDK生成自定义令牌+静态登录页
这个方案利用Admin SDK的自定义令牌能力,搭配临时静态页面完成登录,全程不用改动现有应用:
- 写一个本地Node.js脚本,用项目服务账号密钥初始化Firebase Admin SDK
- 读取CSV里的用户邮箱,确认用户已在Firebase Auth中存在(未导入的话,用
admin.auth().createUser()批量创建)
- 读取CSV里的用户邮箱,确认用户已在Firebase Auth中存在(未导入的话,用
- 对每个用户,用其UID生成自定义令牌:
const token = await admin.auth().createCustomToken(uid)
- 对每个用户,用其UID生成自定义令牌:
- 临时部署一个极简静态页面(比如用Firebase Hosting,用完就删),页面内嵌JS解析URL中的token,调用
firebase.auth().signInWithCustomToken(token)完成登录后跳转到应用主页
- 临时部署一个极简静态页面(比如用Firebase Hosting,用完就删),页面内嵌JS解析URL中的token,调用
- 用
nodemailer之类的邮件库,给每个用户发送包含登录链接的邮件
- 用
核心代码片段
const admin = require('firebase-admin'); const fs = require('fs'); const csv = require('csv-parser'); const nodemailer = require('nodemailer'); // 初始化Admin SDK const serviceAccount = require('./service-account-key.json'); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); // 配置邮件发送器(替换为你的邮箱服务信息) const transporter = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'your-email@gmail.com', pass: 'your-app-specific-password' } }); // 读取CSV并批量处理 fs.createReadStream('users.csv') .pipe(csv()) .on('data', async (row) => { const email = row.email; try { // 获取用户UID(已导入的用户) const userRecord = await admin.auth().getUserByEmail(email); const customToken = await admin.auth().createCustomToken(userRecord.uid); // 构造登录链接 const loginLink = `https://your-temp-login-page.firebaseapp.com/?token=${customToken}`; // 发送邮件 await transporter.sendMail({ from: '你的应用 <your-email@gmail.com>', to: email, subject: '一键登录你的账号', html: `<p>点击下方链接直接登录:<a href="${loginLink}">立即登录</a></p>` }); console.log(`已发送给${email}`); } catch (err) { console.error(`处理${email}失败:`, err); } }) .on('end', () => { console.log('所有用户处理完成'); });
方案二:直接调用Firebase Auth REST API发送官方无密码登录链接
Firebase的REST API支持官方无密码登录链接的发送接口,直接在本地脚本调用即可,无需依赖Admin SDK:
- 从Firebase项目设置中获取Web API密钥
- 构造POST请求到
https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=你的API密钥
- 构造POST请求到
- 请求体包含:
email(用户邮箱)、requestType: "SIGN_IN_LINK"、continueUrl(登录后跳转的应用地址)
- 请求体包含:
- 循环CSV中的邮箱批量发送请求
核心代码片段
const fs = require('fs'); const csv = require('csv-parser'); const fetch = require('node-fetch'); const API_KEY = 'your-firebase-web-api-key'; const CONTINUE_URL = 'https://your-app.com/login-success'; // 需添加到Firebase Auth授权域 fs.createReadStream('users.csv') .pipe(csv()) .on('data', async (row) => { const email = row.email; try { await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, requestType: 'SIGN_IN_LINK', continueUrl: CONTINUE_URL }) }); console.log(`已发送无密码登录链接给${email}`); } catch (err) { console.error(`处理${email}失败:`, err); } }) .on('end', () => { console.log('所有用户处理完成'); });
注意:方案二中的
continueUrl必须添加到Firebase Auth的授权域列表中,否则登录链接会失效。
内容的提问来源于stack exchange,提问作者MadMac
相关产品推荐
相关产品推荐

