如何支持用户名/密码与邮箱/密码两种登录方式?
Firebase 用户名登录匹配邮箱注册用户的解决方案
问题背景
我正尝试简化用户注册流程,不强制要求填写邮箱。用户再次登录时会出现三种情况:
- 用户未使用邮箱注册,后端将其邮箱设为
username@mydomain.com,登录时在用户名后追加@mydomain.com进行认证。 - 用户使用邮箱注册,直接通过邮箱/密码登录。
- 用户使用邮箱注册,但尝试通过用户名/密码登录。
针对第三种情况,我找不到合适的认证方法。最初想法是将用户名和密码发送至Cloud Function,匹配用户名对应的邮箱并验证密码,但Admin SDK似乎无此功能。将邮箱返回给客户端又存在安全隐患,请问是否遗漏了什么?有什么解决方案吗?
最终实现方案
我最终采用了建议的方案,通过Cloud Function结合Firestore映射关系与Firebase身份验证API完成验证,避免直接暴露邮箱给客户端,代码如下:
// The Cloud Functions for Firebase SDK to // create Cloud Functions and set up triggers. const functions = require('firebase-functions'); // The Firebase Admin SDK to access Firestore. const admin = require('firebase-admin'); admin.initializeApp(); const axios = require('axios'); const apiKey = 'API KEY'; const signInURL = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=' + apiKey; exports.getEmail = functions.https.onCall(async (data, context) => { // 获取传入的用户名和密码参数 const username = data.text.toLowerCase(); const password = data.password; // 通过用户名查询对应的UID const uidData = await admin .firestore() .collection('usernameToUid') .doc(username) .get(); const uid = uidData.get('uid'); if (uid == null) { return {result: 'auth/user-not-found'}; } // 通过UID查询对应的邮箱 const emailData = await admin .firestore() .collection('emails') .doc(uid) .get(); const email = emailData.get('email'); if (email == null) { return {result: 'auth/email-not-found'}; } // 调用Firebase身份验证API验证密码 try { const response = await axios .post(signInURL, { email: email, password: password, returnSecureToken: true, }); return {result: response.data.email}; } catch (error) { return {result: 'auth/incorrect-password'}; } });
实现逻辑说明
- 在Firestore中维护两个集合:
usernameToUid:存储用户名到用户UID的映射,文档ID为用户名,字段包含对应UIDemails:存储用户UID到邮箱的映射,文档ID为UID,字段包含用户邮箱
- Cloud Function接收客户端传入的用户名和密码,先通过用户名找到对应的UID
- 再通过UID找到用户的邮箱
- 调用Firebase的
signInWithPasswordAPI验证邮箱和密码的正确性,验证通过后返回邮箱,失败则返回对应的错误标识
内容的提问来源于stack exchange,提问作者KnowNothing
相关产品推荐
相关产品推荐

