FirebaseUI 是以 Firebase Authentication SDK 为基础构建的库,提供适合在应用中使用的普适性界面流程。FirebaseUI 具有以下优势:
- 多提供方 - 支持电子邮件/密码、电子邮件链接、电话身份验证、Google、Facebook、Twitter 和 GitHub 登录流程。
- 账号关联 - 用于将各种身份提供方安全地关联到用户账号的流程。
- 自定义 - 重写 FirebaseUI 的 CSS 样式,使其符合您的应用要求。另外,FirebaseUI 是开源的,因此您可以克隆 (fork) 项目,并根据您的需求对其进行深度定制。
- 一键注册和自动登录 - 自动集成一键注册,实现快速跨设备登录。
- 本地化的界面 - 支持 40 多种语言。
- 升级匿名用户 - 可以通过登录/注册升级匿名用户。如需了解详情,请访问升级匿名用户部分。
准备工作
将 Firebase Authentication 添加到您的 Web 应用,确保您使用的是 v9 兼容型 SDK(推荐)或旧版 SDK(请参阅上面的边栏)。
通过以下方法添加 FirebaseUI:
CDN
从 Firebase 控制台中,将以下脚本和 CSS 文件添加到页面的 <head> 标记中,位于初始化代码段的下方:
<script src="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.js"></script> <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css" />
npm 模块
使用以下命令,通过 npm 安装 FirebaseUI 及其依赖项:
$ npm install firebaseui --save
在源代码文件中使用
require
指定以下必需模块:var firebase = require('firebase'); var firebaseui = require('firebaseui');
Bower 组件
使用以下命令,通过 Bower 安装 FirebaseUI 及其依赖项:
$ bower install firebaseui --save
将所需文件添加到 HTML 中(假设文件位于您的 HTTP 服务器的
bower_components/
路径中):<script src="bower_components/firebaseui/dist/firebaseui.js"></script> <link type="text/css" rel="stylesheet" href="bower_components/firebaseui/dist/firebaseui.css" />
初始化 FirebaseUI
导入 SDK 后,初始化身份验证界面。
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
设置登录方法
您必须先启用并配置您希望支持的登录方法,然后用户才能通过 Firebase 登录。
电子邮件地址和密码
在 Firebase 控制台中,打开 Authentication 部分并启用电子邮件地址和密码身份验证方式。
将电子邮件服务提供方 ID 添加到 FirebaseUI
signInOptions
列表中。ui.start('#firebaseui-auth-container', { signInOptions: [ firebase.auth.EmailAuthProvider.PROVIDER_ID ], // Other config options... });
可选:您可以将
EmailAuthProvider
配置为要求用户输入显示名(默认为true
)。ui.start('#firebaseui-auth-container', { signInOptions: [ { provider: firebase.auth.EmailAuthProvider.PROVIDER_ID, requireDisplayName: false } ] });
电子邮件链接身份验证
在 Firebase 控制台中,打开 Authentication 部分。在 Sign in method(登录方法)标签页中,启用电子邮件地址/密码提供方。请注意,必须启用电子邮件地址/密码登录才能使用电子邮件链接登录流程。
在同一部分中,启用电子邮件链接(无密码登录)登录方法,然后点击保存。
将电子邮件服务提供方 ID 添加到 FirebaseUI
signInOptions
以及电子邮件链接signInMethod
的列表中。ui.start('#firebaseui-auth-container', { signInOptions: [ { provider: firebase.auth.EmailAuthProvider.PROVIDER_ID, signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD } ], // Other config options... });
有条件地呈现登录界面(与单页应用相关)时,使用
ui.isPendingRedirect()
检测网址是否对应于使用电子邮件链接的登录,因此需要呈现该界面以完成登录。// Is there an email link sign-in? if (ui.isPendingRedirect()) { ui.start('#firebaseui-auth-container', uiConfig); } // This can also be done via: if (firebase.auth().isSignInWithEmailLink(window.location.href)) { ui.start('#firebaseui-auth-container', uiConfig); }
可选:您可以将用于电子邮件链接登录的
EmailAuthProvider
配置为允许或阻止用户完成跨设备登录。可以定义一个可选的
emailLinkSignIn
回调,以返回要在发送链接时使用的firebase.auth.ActionCodeSettings
配置。这可让您指定该链接的处理方式、自定义动态链接、深层链接中的其他状态等。如果未提供,则使用当前网址并触发 Web 专属流程。“FirebaseUI-Web”中的电子邮件链接登录与 FirebaseUI-Android 和 FirebaseUI-iOS 兼容(从 FirebaseUI-Android 启动该流程的用户可以打开链接并使用“FirebaseUI-Web”完成登录)。对于反向流程也是如此。
ui.start('#firebaseui-auth-container', { signInOptions: [ { provider: firebase.auth.EmailAuthProvider.PROVIDER_ID, signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD, // Allow the user the ability to complete sign-in cross device, // including the mobile apps specified in the ActionCodeSettings // object below. forceSameDevice: false, // Used to define the optional firebase.auth.ActionCodeSettings if // additional state needs to be passed along request and whether to open // the link in a mobile app if it is installed. emailLinkSignIn: function() { return { // Additional state showPromo=1234 can be retrieved from URL on // sign-in completion in signInSuccess callback by checking // window.location.href. url: 'https://www.example.com/completeSignIn?showPromo=1234', // Custom FDL domain. dynamicLinkDomain: 'example.page.link', // Always true for email link sign-in. handleCodeInApp: true, // Whether to handle link in iOS app if installed. iOS: { bundleId: 'com.example.ios' }, // Whether to handle link in Android app if opened in an Android // device. android: { packageName: 'com.example.android', installApp: true, minimumVersion: '12' } }; } } ] });
OAuth 提供方(Google、Facebook、Twitter 和 GitHub)
在 Firebase 控制台中,打开 Authentication 部分并启用指定的 OAuth 提供方登录机制。确保指定了相应的 OAuth 客户端 ID 和密钥。
同样在 Authentication 部分中,确保将呈现登录页面的网域添加到已获授权的网域列表中。
将 OAuth 提供方 ID 添加到 FirebaseUI
signInOptions
列表中。ui.start('#firebaseui-auth-container', { signInOptions: [ // List of OAuth providers supported. firebase.auth.GoogleAuthProvider.PROVIDER_ID, firebase.auth.FacebookAuthProvider.PROVIDER_ID, firebase.auth.TwitterAuthProvider.PROVIDER_ID, firebase.auth.GithubAuthProvider.PROVIDER_ID ], // Other config options... });
可选:如需指定自定义范围,或按提供方指定自定义 OAuth 参数,您可以传递一个对象(而不仅仅是提供方的值):
ui.start('#firebaseui-auth-container', { signInOptions: [ { provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID, scopes: [ 'https://www.googleapis.com/auth/contacts.readonly' ], customParameters: { // Forces account selection even when one account // is available. prompt: 'select_account' } }, { provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID, scopes: [ 'public_profile', 'email', 'user_likes', 'user_friends' ], customParameters: { // Forces password re-entry. auth_type: 'reauthenticate' } }, firebase.auth.TwitterAuthProvider.PROVIDER_ID, // Twitter does not support scopes. firebase.auth.EmailAuthProvider.PROVIDER_ID // Other providers don't need to be given as object. ] });
电话号码
在 Firebase 控制台中,打开 Authentication 部分并启用电话号码登录服务。
确保将呈现登录页面的网域也添加到已获授权的网域列表中。
将电话号码提供方 ID 添加到 FirebaseUI
signInOptions
列表中。ui.start('#firebaseui-auth-container', { signInOptions: [ firebase.auth.PhoneAuthProvider.PROVIDER_ID ], // Other config options... });
可选:您可以使用自定义 reCAPTCHA 参数来配置 PhoneAuthProvider,无论 reCAPTCHA 是否可见(默认为正常)。请参阅 reCAPTCHA API 文档了解详情。
您也可以设置电话号码输入字段的默认国家/地区。如需完整的代码列表,请参阅支持的国家/地区代码列表。如果未指定,电话号码输入字段将默认为美国 (+1)。
目前,系统支持以下选项。
ui.start('#firebaseui-auth-container', { signInOptions: [ { provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID, recaptchaParameters: { type: 'image', // 'audio' size: 'normal', // 'invisible' or 'compact' badge: 'bottomleft' //' bottomright' or 'inline' applies to invisible. }, defaultCountry: 'GB', // Set default country to the United Kingdom (+44). // For prefilling the national number, set defaultNationNumber. // This will only be observed if only phone Auth provider is used since // for multiple providers, the NASCAR screen will always render first // with a 'sign in with phone number' button. defaultNationalNumber: '1234567890', // You can also pass the full phone number string instead of the // 'defaultCountry' and 'defaultNationalNumber'. However, in this case, // the first country ID that matches the country code will be used to // populate the country selector. So for countries that share the same // country code, the selected country may not be the expected one. // In that case, pass the 'defaultCountry' instead to ensure the exact // country is selected. The 'defaultCountry' and 'defaultNationaNumber' // will always have higher priority than 'loginHint' which will be ignored // in their favor. In this case, the default country will be 'GB' even // though 'loginHint' specified the country code as '+1'. loginHint: '+11234567890' } ] });
登录
如需启动 FirebaseUI 登录流程,请通过传递底层的 Auth
实例来初始化 FirebaseUI 实例。
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
定义要在其中呈现 FirebaseUI 登录微件的 HTML 元素。
<!-- The surrounding HTML is left untouched by FirebaseUI.
Your app may use that space for branding, controls and other customizations.-->
<h1>Welcome to My Awesome App</h1>
<div id="firebaseui-auth-container"></div>
<div id="loader">Loading...</div>
指定 FirebaseUI 配置(如支持的提供方、界面自定义和成功回调函数等)。
var uiConfig = {
callbacks: {
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
// User successfully signed in.
// Return type determines whether we continue the redirect automatically
// or whether we leave that to developer to handle.
return true;
},
uiShown: function() {
// The widget is rendered.
// Hide the loader.
document.getElementById('loader').style.display = 'none';
}
},
// Will use popup for IDP Providers sign-in flow instead of the default, redirect.
signInFlow: 'popup',
signInSuccessUrl: '<url-to-redirect-to-on-success>',
signInOptions: [
// Leave the lines as is for the providers you want to offer your users.
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
firebase.auth.TwitterAuthProvider.PROVIDER_ID,
firebase.auth.GithubAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID,
firebase.auth.PhoneAuthProvider.PROVIDER_ID
],
// Terms of service url.
tosUrl: '<your-tos-url>',
// Privacy policy url.
privacyPolicyUrl: '<your-privacy-policy-url>'
};
最后,呈现 FirebaseUI 身份验证界面:
// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);
升级匿名用户
启用匿名用户升级功能
当匿名用户使用永久账号登录或注册后,您需要确保该用户可以继续其注册之前进行的操作。为此,您只需在配置登录界面时将 autoUpgradeAnonymousUsers
设置为 true
即可(此选项默认处于停用状态)。
处理匿名用户升级时发生的合并冲突
有时,最初以匿名方式登录的用户会尝试升级到一个现有的 Firebase 用户。由于现有用户无法关联到其他现有用户,因此,当发生上述情况时,FirebaseUI 将触发 signInFailure
回调函数并返回错误代码 firebaseui/anonymous-upgrade-merge-conflict
。error 对象还将包含永久凭据。应在回调函数中触发使用永久凭据登录的机制来完成登录。如需通过 auth.signInWithCredential(error.credential)
完成登录,您必须先保存匿名用户的数据并删除匿名用户。然后,在登录完成后,将数据复制回非匿名用户。以下示例说明了此登录流程的工作原理。
// Temp variable to hold the anonymous user data if needed.
var data = null;
// Hold a reference to the anonymous current user.
var anonymousUser = firebase.auth().currentUser;
ui.start('#firebaseui-auth-container', {
// Whether to upgrade anonymous users should be explicitly provided.
// The user must already be signed in anonymously before FirebaseUI is
// rendered.
autoUpgradeAnonymousUsers: true,
signInSuccessUrl: '<url-to-redirect-to-on-success>',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID,
firebase.auth.PhoneAuthProvider.PROVIDER_ID
],
callbacks: {
// signInFailure callback must be provided to handle merge conflicts which
// occur when an existing credential is linked to an anonymous user.
signInFailure: function(error) {
// For merge conflicts, the error.code will be
// 'firebaseui/anonymous-upgrade-merge-conflict'.
if (error.code != 'firebaseui/anonymous-upgrade-merge-conflict') {
return Promise.resolve();
}
// The credential the user tried to sign in with.
var cred = error.credential;
// Copy data from anonymous user to permanent user and delete anonymous
// user.
// ...
// Finish sign-in after data is copied.
return firebase.auth().signInWithCredential(cred);
}
}
});
后续步骤
- 如需详细了解如何使用和自定义 FirebaseUI,请参阅 README 文件。
- 如果您发现 FirebaseUI 中存在问题并希望进行报告,请使用 GitHub 问题跟踪器。