In diesem Dokument erfahren Sie, wie Sie mithilfe der Firebase-Authentifizierung Benutzer bei einer Chrome-Erweiterung anmelden, die Manifest V3 verwendet.
Firebase Authentication bietet mehrere Authentifizierungsmethoden zum Anmelden von Benutzern über eine Chrome-Erweiterung, wobei einige mehr Entwicklungsaufwand erfordern als andere.
Um die folgenden Methoden in einer Manifest V3 Chrome-Erweiterung zu verwenden, müssen Sie sie nur aus firebase/auth/web-extension
importieren :
- Melden Sie sich mit E-Mail und Passwort an (
createUserWithEmailAndPassword
undsignInWithEmailAndPassword
) - Melden Sie sich mit einem E-Mail-Link an (
sendSignInLinkToEmail
,isSignInWithEmailLink
undsignInWithEmailLink
) - Anonym anmelden (
signInAnonymously
) - Melden Sie sich mit einem benutzerdefinierten Authentifizierungssystem an (
signInWithCustomToken
) - Behandeln Sie die Anbieteranmeldung unabhängig und verwenden Sie dann
signInWithCredential
Die folgenden Anmeldemethoden werden ebenfalls unterstützt, erfordern jedoch etwas zusätzlichen Aufwand:
- Melden Sie sich mit einem Popup-Fenster an (
signInWithPopup
,linkWithPopup
undreauthenticateWithPopup
) - Melden Sie sich an, indem Sie zur Anmeldeseite weiterleiten (
signInWithRedirect
,linkWithRedirect
undreauthenticateWithRedirect
). - Melden Sie sich mit der Telefonnummer mit reCAPTCHA an
- SMS-Multifaktor-Authentifizierung mit reCAPTCHA
- reCAPTCHA Enterprise-Schutz
Um diese Methoden in einer Manifest V3 Chrome-Erweiterung zu verwenden, müssen Sie Offscreen Documents verwenden.
Verwenden Sie den Einstiegspunkt firebase/auth/web-extension
Durch den Import aus firebase/auth/web-extension
erfolgt die Anmeldung von Benutzern über eine Chrome-Erweiterung ähnlich wie bei einer Web-App.
firebase/auth/web-extension wird nur auf den Web SDK-Versionen v10.8.0 und höher unterstützt.
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth/web-extension'; const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) .then((userCredential) => { // Signed in const user = userCredential.user; // ... }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; });
Verwenden Sie Offscreen-Dokumente
Einige Authentifizierungsmethoden wie signInWithPopup
, linkWithPopup
und reauthenticateWithPopup
sind nicht direkt mit Chrome-Erweiterungen kompatibel, da sie das Laden von Code von außerhalb des Erweiterungspakets erfordern. Ab Manifest V3 ist dies nicht zulässig und wird von der Erweiterungsplattform blockiert. Um dies zu umgehen, können Sie diesen Code mithilfe eines Offscreen-Dokuments in einen Iframe laden. Implementieren Sie im Offscreen-Dokument den normalen Authentifizierungsablauf und leiten Sie das Ergebnis aus dem Offscreen-Dokument zurück an die Erweiterung.
In dieser Anleitung wird signInWithPopup
als Beispiel verwendet, das gleiche Konzept gilt jedoch auch für andere Authentifizierungsmethoden.
Bevor Sie beginnen
Für diese Technik müssen Sie eine im Web verfügbare Webseite einrichten, die Sie in einen Iframe laden. Hierfür eignet sich jeder Host, einschließlich Firebase Hosting . Erstellen Sie eine Website mit folgendem Inhalt:
<!DOCTYPE html> <html> <head> <title>signInWithPopup</title> <script src="signInWithPopup.js"></script> </head> <body><h1>signInWithPopup</h1></body> </html>
Verbundanmeldung
Wenn Sie die Verbundanmeldung verwenden, z. B. die Anmeldung mit Google, Apple, SAML oder OIDC, müssen Sie Ihre Chrome-Erweiterungs-ID zur Liste der autorisierten Domänen hinzufügen:
- Öffnen Sie Ihr Projekt in der Firebase-Konsole .
- Öffnen Sie im Abschnitt Authentifizierung die Seite Einstellungen .
- Fügen Sie der Liste der autorisierten Domänen einen URI wie den folgenden hinzu:
chrome-extension://CHROME_EXTENSION_ID
Stellen Sie in der Manifestdatei Ihrer Chrome-Erweiterung sicher, dass Sie die folgenden URLs zur Zulassungsliste content_security_policy
hinzufügen:
-
https://apis.google.com
-
https://www.gstatic.com
-
https://www.googleapis.com
-
https://securetoken.googleapis.com
Implementieren Sie die Authentifizierung
In Ihrem HTML-Dokument ist signInWithPopup.js der JavaScript-Code, der die Authentifizierung übernimmt. Es gibt zwei verschiedene Möglichkeiten, eine Methode zu implementieren, die direkt in der Erweiterung unterstützt wird:
- Verwenden Sie
firebase/auth
anstelle vonfirebase/auth/web-extension
. Der Einstiegspunkt derweb-extension
dient für Code, der innerhalb der Erweiterung ausgeführt wird. Während dieser Code letztendlich in der Erweiterung ausgeführt wird (in einem Iframe, in Ihrem Offscreen-Dokument), ist der Kontext, in dem er ausgeführt wird, das Standard-Web. - Binden Sie die Authentifizierungslogik in einen
postMessage
Listener ein, um die Authentifizierungsanfrage und -antwort weiterzuleiten.
import { signInWithPopup, GoogleAuthProvider, getAuth } from'firebase/auth'; import { initializeApp } from 'firebase/app'; import firebaseConfig from './firebaseConfig.js' const app = initializeApp(firebaseConfig); const auth = getAuth(); // This code runs inside of an iframe in the extension's offscreen document. // This gives you a reference to the parent frame, i.e. the offscreen document. // You will need this to assign the targetOrigin for postMessage. const PARENT_FRAME = document.location.ancestorOrigins[0]; // This demo uses the Google auth provider, but any supported provider works. // Make sure that you enable any provider you want to use in the Firebase Console. // https://console.firebase.google.com/project/_/authentication/providers const PROVIDER = new GoogleAuthProvider(); function sendResponse(result) { globalThis.parent.self.postMessage(JSON.stringify(result), PARENT_FRAME); } globalThis.addEventListener('message', function({data}) { if (data.initAuth) { // Opens the Google sign-in page in a popup, inside of an iframe in the // extension's offscreen document. // To centralize logic, all respones are forwarded to the parent frame, // which goes on to forward them to the extension's service worker. signInWithPopup(auth, PROVIDER) .then(sendResponse) .catch(sendResponse) } });
Erstellen Sie Ihre Chrome-Erweiterung
Nachdem Ihre Website online ist, können Sie sie in Ihrer Chrome-Erweiterung verwenden.
- Fügen Sie die
offscreen
Berechtigung zu Ihrer manifest.json-Datei hinzu: - Erstellen Sie das Offscreen-Dokument selbst. Dies ist eine minimale HTML-Datei in Ihrem Erweiterungspaket, die die Logik Ihres Offscreen-Dokument-JavaScripts lädt:
- Fügen Sie
offscreen.js
in Ihr Erweiterungspaket ein. Es fungiert als Proxy zwischen der in Schritt 1 eingerichteten öffentlichen Website und Ihrer Erweiterung. - Richten Sie das Offscreen-Dokument über Ihren Background.js-Servicemitarbeiter ein.
{ "name": "signInWithPopup Demo", "manifest_version" 3, "background": { "service_worker": "background.js" }, "permissions": [ "offscreen" ] }
<!DOCTYPE html> <script src="./offscreen.js"></script>
// This URL must point to the public site const _URL = 'https://example.com/signInWithPopupExample'; const iframe = document.createElement('iframe'); iframe.src = _URL; document.documentElement.appendChild(iframe); chrome.runtime.onMessage.addListener(handleChromeMessages); function handleChromeMessages(message, sender, sendResponse) { // Extensions may have an number of other reasons to send messages, so you // should filter out any that are not meant for the offscreen document. if (message.target !== 'offscreen') { return false; } function handleIframeMessage({data}) { try { if (data.startsWith('!_{')) { // Other parts of the Firebase library send messages using postMessage. // You don't care about them in this context, so return early. return; } data = JSON.parse(data); self.removeEventListener('message', handleIframeMessage); sendResponse(data); } catch (e) { console.log(`json parse failed - ${e.message}`); } } globalThis.addEventListener('message', handleIframeMessage, false); // Initialize the authentication flow in the iframed document. You must set the // second argument (targetOrigin) of the message in order for it to be successfully // delivered. iframe.contentWindow.postMessage({"initAuth": true}, new URL(_URL).origin); return true; }
const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html'; // A global promise to avoid concurrency issues let creatingOffscreenDocument; // Chrome only allows for a single offscreenDocument. This is a helper function // that returns a boolean indicating if a document is already active. async function hasDocument() { // Check all windows controlled by the service worker to see if one // of them is the offscreen document with the given path const matchedClients = await clients.matchAll(); return matchedClients.some( (c) => c.url === chrome.runtime.getURL(OFFSCREEN_DOCUMENT_PATH) ); } async function setupOffscreenDocument(path) { // If we do not have a document, we are already setup and can skip if (!(await hasDocument())) { // create offscreen document if (creating) { await creating; } else { creating = chrome.offscreen.createDocument({ url: path, reasons: [ chrome.offscreen.Reason.DOM_SCRAPING ], justification: 'authentication' }); await creating; creating = null; } } } async function closeOffscreenDocument() { if (!(await hasDocument())) { return; } await chrome.offscreen.closeDocument(); } function getAuth() { return new Promise(async (resolve, reject) => { const auth = await chrome.runtime.sendMessage({ type: 'firebase-auth', target: 'offscreen' }); auth?.name !== 'FirebaseError' ? resolve(auth) : reject(auth); }) } async function firebaseAuth() { await setupOffscreenDocument(OFFSCREEN_DOCUMENT_PATH); const auth = await getAuth() .then((auth) => { console.log('User Authenticated', auth); return auth; }) .catch(err => { if (err.code === 'auth/operation-not-allowed') { console.error('You must enable an OAuth provider in the Firebase' + ' console in order to use signInWithPopup. This sample' + ' uses Google by default.'); } else { console.error(err); return err; } }) .finally(closeOffscreenDocument) return auth; }
Wenn Sie nun firebaseAuth()
in Ihrem Service Worker aufrufen, wird das Offscreen-Dokument erstellt und die Site in einen Iframe geladen. Dieser Iframe wird im Hintergrund verarbeitet und Firebase durchläuft den Standardauthentifizierungsablauf. Sobald das Problem gelöst oder abgelehnt wurde, wird das Authentifizierungsobjekt mithilfe des Offscreen-Dokuments von Ihrem Iframe an Ihren Servicemitarbeiter weitergeleitet.