如何在GCP/Firebase中搭建多应用共享的集中式身份认证项目?
跨应用共享Firebase账号方案实现
针对你提出的集中式认证+跨应用共享账号需求,完全可以通过Firebase Functions实现,iOS前端也能完成所有核心操作;同时多Firebase配置文件的区分也有成熟的处理方式,具体方案如下:
一、核心实现逻辑
以Project A作为唯一的认证源和用户数据存储中心,Project B/C不启用本地邮箱/密码认证,可通过两种方式对接Project A:
- 调用Project A部署的Firebase Functions完成注册/登录,获取自定义token后登录Project A的Auth系统;
- 直接在iOS端初始化Project A的Firebase实例,用其Auth SDK完成原生邮箱/密码认证(更简洁,无需Functions)。
二、Firebase Functions 实现方案(部署在Project A)
如果需要自定义认证逻辑(比如额外参数校验、关联业务数据),可以用Functions封装注册/登录接口:
1. 用户注册接口
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.createUser = functions.https.onCall(async (data) => { const { email, password, displayName } = data; try { // 创建Project A的认证用户 const user = await admin.auth().createUser({ email, password, displayName }); // 写入基础用户信息到Firestore await admin.firestore().collection("users").doc(user.uid).set({ email, displayName, createdAt: admin.firestore.FieldValue.serverTimestamp() }); // 返回自定义token供客户端登录 const customToken = await admin.auth().createCustomToken(user.uid); return { customToken, uid: user.uid }; } catch (err) { throw new functions.https.HttpsError("invalid-argument", err.message); } });
2. 用户登录接口
exports.signInUser = functions.https.onCall(async (data) => { const { email } = data; try { const user = await admin.auth().getUserByEmail(email); const customToken = await admin.auth().createCustomToken(user.uid); return { customToken, uid: user.uid }; } catch (err) { throw new functions.https.HttpsError("invalid-argument", err.message); } });
三、iOS前端操作实现
方式1:通过Functions对接(适合自定义逻辑场景)
- 初始化当前应用的Firebase项目(Project B/C),添加Firebase Functions依赖;
- 手动创建Project A的Firebase配置,初始化其Auth实例:
// 初始化Project A的Firebase App let projectAOptions = FirebaseOptions( googleAppID: "PROJECT_A_GOOGLE_APP_ID", gcmSenderID: "PROJECT_A_GCM_SENDER_ID" ) projectAOptions.apiKey = "PROJECT_A_API_KEY" projectAOptions.projectID = "PROJECT_A_PROJECT_ID" projectAOptions.bundleID = Bundle.main.bundleIdentifier! FirebaseApp.configure(name: "ProjectA", options: projectAOptions) // 获取Project A的Auth实例 guard let projectAAuth = Auth.auth(app: FirebaseApp.app(name: "ProjectA")) else { return } // 调用Project A的登录函数 let functions = Functions.functions(region: "your-region") functions.httpsCallable("signInUser").call(["email": "user@example.com"]) { result, error in guard let customToken = (result?.data as? [String: Any])?["customToken"] as? String else { return } // 用自定义token登录Project A的Auth projectAAuth.signIn(withCustomToken: customToken) { authResult, error in if let user = authResult?.user { // 登录成功,访问Project A的Firestore let projectAFirestore = Firestore.firestore(app: FirebaseApp.app(name: "ProjectA")) projectAFirestore.collection("users").document(user.uid).getDocument { snapshot, _ in print("用户数据:\(snapshot?.data() ?? [:])") } } } }
方式2:直接多项目初始化(更简洁)
如果不需要自定义逻辑,直接在iOS端同时初始化两个Firebase项目:
- 将Project A的
GoogleService-Info.plist重命名为GoogleService-Info-ProjectA.plist,添加到项目中; - 初始化双项目并登录:
// 初始化当前应用的主项目(Project B/C) FirebaseApp.configure() // 初始化Project A guard let plistPath = Bundle.main.path(forResource: "GoogleService-Info-ProjectA", ofType: "plist"), let options = FirebaseOptions(contentsOfFile: plistPath) else { return } FirebaseApp.configure(name: "ProjectA", options: options) // 用Project A的Auth登录 guard let projectAAuth = Auth.auth(app: FirebaseApp.app(name: "ProjectA")) else { return } projectAAuth.signIn(withEmail: "user@example.com", password: "123456") { authResult, error in if let user = authResult?.user { // 访问Project A的Firestore let firestore = Firestore.firestore(app: FirebaseApp.app(name: "ProjectA")) firestore.collection("users").document(user.uid).getDocument { snapshot, _ in // 处理用户数据 } } }
四、iOS中区分多个Firebase配置的方法
- 文件重命名:将不同项目的配置文件重命名(如
GoogleService-Info-ProjectA.plist),避免文件名冲突; - 指定App名称初始化:初始化时给每个Firebase App分配唯一名称(如
ProjectA),后续通过FirebaseApp.app(name: "ProjectA")获取对应项目的Auth、Firestore等实例; - 代码硬编码配置:如果不想添加多个plist文件,直接在代码中创建
FirebaseOptions并填入对应项目的API Key、Project ID等参数,灵活度更高。
五、关键注意事项
- 权限配置:在Project A的Firestore中设置安全规则,确保只有已认证用户能访问自己的数据:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{uid} { allow read, write: if request.auth != null && request.auth.uid == uid; } } }
- 控制台配置:在Project A的Firebase控制台添加所有客户端App的Bundle ID,否则无法正常初始化Auth SDK;
- Token过期处理:自定义token默认有效期1小时,客户端需监听Auth的
didChangeAuthState事件,及时刷新token。
内容的提问来源于stack exchange,提问作者Joe Alvini
相关产品推荐
相关产品推荐

