Questo documento mostra come utilizzare Identity Platform per consentire agli utenti di accedere a un'estensione di Chrome che utilizza Manifest V3.
Identity Platform offre più metodi di autenticazione per l'accesso degli utenti da un'estensione di Chrome, alcuni dei quali richiedono più impegno di sviluppo rispetto ad altri.
Per utilizzare i seguenti metodi in un'estensione Chrome Manifest V3, devi solo
importarli da firebase/auth/web-extension
:
- Accedi con email e password (
createUserWithEmailAndPassword
esignInWithEmailAndPassword
) - Accedi con il link via email (
sendSignInLinkToEmail
,isSignInWithEmailLink
esignInWithEmailLink
) - Accedere in modalità anonima (
signInAnonymously
) - Accedere con un sistema di autenticazione personalizzato (
signInWithCustomToken
) - Gestisci l'accesso del fornitore in modo indipendente, poi utilizza
signInWithCredential
Sono supportati anche i seguenti metodi di accesso, ma richiedono un lavoro aggiuntivo:
- Accedere con una finestra popup (
signInWithPopup
,linkWithPopup
ereauthenticateWithPopup
) - Accedi reindirizzando alla pagina di accesso (
signInWithRedirect
,linkWithRedirect
ereauthenticateWithRedirect
) - Accedere con il numero di telefono con reCAPTCHA
- Autenticazione a più fattori tramite SMS con reCAPTCHA
- Protezione reCAPTCHA Enterprise
Per utilizzare questi metodi in un'estensione Chrome Manifest V3, devi utilizzare Documenti offscreen.
Utilizza il punto di ingresso firebase/auth/web-extension
L'importazione da firebase/auth/web-extension
rende l'accesso degli utenti da un'estensione di Chrome simile a quello di un'app web.
firebase/auth/web-extension è supportato solo nelle versioni v10.8.0 e successive dell'SDK web.
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; });
Utilizzare i documenti fuori schermo
Alcuni metodi di autenticazione, come signInWithPopup
, linkWithPopup
e
reauthenticateWithPopup
, non sono direttamente compatibili con le estensioni di Chrome,
perché richiedono il caricamento del codice dall'esterno del pacchetto dell'estensione.
A partire da Manifest V3, questa operazione non è consentita e verrà bloccata dalla
piattaforma delle estensioni. Per risolvere questo problema, puoi caricare il codice all'interno
di un iframe utilizzando un documento fuori schermo.
Nel documento fuori schermo, implementa il normale flusso di autenticazione e invia tramite proxy il risultato dal documento fuori schermo all'estensione.
Questa guida utilizza signInWithPopup
come esempio, ma lo stesso concetto
si applica ad altri metodi di autenticazione.
Prima di iniziare
Questa tecnica richiede di configurare una pagina web disponibile sul web che caricherai in un iframe. Qualsiasi host funziona, incluso Firebase Hosting. Crea un sito web con i seguenti contenuti:
<!DOCTYPE html> <html> <head> <title>signInWithPopup</title> <script src="signInWithPopup.js"></script> </head> <body><h1>signInWithPopup</h1></body> </html>
Accesso federato
Se utilizzi l'accesso federato, ad esempio l'accesso con Google, Apple, SAML o OIDC, devi aggiungere l'ID della tua estensione Chrome all'elenco dei domini autorizzati:
Vai alla pagina Impostazioni di Identity Platform nella consoleGoogle Cloud .
Seleziona la scheda Sicurezza.
In Domini autorizzati, fai clic su Aggiungi dominio.
Inserisci l'URI dell'estensione. Dovrebbe avere un aspetto simile a questo:
chrome-extension://CHROME_EXTENSION_ID
.Fai clic su Aggiungi.
Nel file manifest dell'estensione Chrome, assicurati di aggiungere i seguenti
URL all'allowlist content_security_policy
:
https://apis.google.com
https://www.gstatic.com
https://www.googleapis.com
https://securetoken.googleapis.com
Implementare l'autenticazione
Nel documento HTML, signInWithPopup.js è il codice JavaScript che gestisce l'autenticazione. Esistono due modi diversi per implementare un metodo supportato direttamente nell'estensione:
- Utilizza
firebase/auth/web-extension
nel codice dell'estensione, ad esempio script di background, service worker o script popup. Utilizzafirebase/auth
solo all'interno dell'iframe offscreen, perché questo iframe viene eseguito in un contesto di pagina web standard. - Inserisci la logica di autenticazione in un listener
postMessage
per eseguire il proxy della richiesta e della risposta di autenticazione.
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) } });
Crea la tua estensione di Chrome
Una volta pubblicato il tuo sito web, puoi utilizzarlo nella tua estensione Chrome.
- Aggiungi l'autorizzazione
offscreen
al file manifest.json: - Crea il documento fuori schermo. Si tratta di un file HTML minimo all'interno del pacchetto dell'estensione che carica la logica del JavaScript del documento fuori schermo:
- Includi
offscreen.js
nel pacchetto dell'estensione. Funge da proxy tra il sito web pubblico configurato nel passaggio 1 e la tua estensione. - Configura il documento offscreen dal service worker background.js.
{ "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; }
import { getAuth } from 'firebase/auth/web-extension'; 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; }
Ora, quando chiami firebaseAuth()
all'interno del service worker, verrà creato
il documento offscreen e il sito verrà caricato in un iframe. Questo iframe verrà elaborato
in background e Firebase seguirà il flusso di autenticazione
standard. Una volta risolto o rifiutato, l'oggetto di autenticazione
verrà sottoposto a proxy dall'iframe al service worker, utilizzando il documento
offscreen.