Z tego dokumentu dowiesz się, jak używać Firebase Authentication do logowania użytkowników w Chrome rozszerzenie, które korzysta z platformy Manifest V3.
Firebase Authentication udostępnia kilka metod uwierzytelniania do logowania użytkowników rozszerzenie do Chrome. Niektóre z nich wymagają większego nakładu pracy niż inne.
Aby korzystać z tych metod w rozszerzeniu Manifest V3 do Chrome, potrzebujesz tylko
zaimportuj je z usługi firebase/auth/web-extension
:
- Zaloguj się za pomocą adresu e-mail i hasła (
createUserWithEmailAndPassword
isignInWithEmailAndPassword
) - Zaloguj się za pomocą linku do logowania w e-mailu (
sendSignInLinkToEmail
,isSignInWithEmailLink
isignInWithEmailLink
) - Zaloguj się anonimowo (
signInAnonymously
) - Zaloguj się za pomocą niestandardowego systemu uwierzytelniania (
signInWithCustomToken
) - Przeprowadź niezależne logowanie dostawcy, a potem użyj
signInWithCredential
Te metody logowania są również obsługiwane, ale wymagają wykonania dodatkowych czynności:
- Zaloguj się w wyskakującym okienku (
signInWithPopup
,linkWithPopup
ireauthenticateWithPopup
) - Zaloguj się przez przekierowanie na stronę logowania (
signInWithRedirect
,linkWithRedirect
ireauthenticateWithRedirect
) - Zaloguj się z użyciem numeru telefonu za pomocą reCAPTCHA
- Uwierzytelnianie wielopoziomowe z użyciem SMS-ów przy użyciu reCAPTCHA
- Ochrona reCAPTCHA Enterprise
Aby używać tych metod w rozszerzeniu do Chrome Manifest V3, musisz użyć Dokumenty poza ekranem.
Używanie punktu wejścia firebase/auth/web-extension
Importowanie z usługi firebase/auth/web-extension
powoduje zalogowanie użytkowników z
Rozszerzenie do Chrome podobne do aplikacji internetowej.
Obiekt firebase/auth/web-extension jest obsługiwany tylko przez pakiet SDK Web SDK w wersji 10.8.0 i innych.
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; });
Używaj dokumentów poza ekranem
niektóre metody uwierzytelniania, takie jak signInWithPopup
, linkWithPopup
i
reauthenticateWithPopup
, nie są bezpośrednio zgodne z rozszerzeniami do Chrome,
bo wymagają one załadowania kodu spoza pakietu rozszerzeń.
Począwszy od platformy Manifest V3 jest to niedozwolone i będzie blokowane przez
z platformy rozszerzenia. Aby obejść ten problem, możesz wczytać ten kod w ciągu
w elemencie iframe przy użyciu dokumentu poza ekranem.
W dokumencie spoza ekranu zaimplementuj normalny proces uwierzytelniania i zastosuj serwer proxy
z dokumentu poza ekranem do rozszerzenia.
W tym przewodniku używamy przykładu: signInWithPopup
, ale ta sama koncepcja
a także inne metody uwierzytelniania.
Zanim zaczniesz
Ta metoda wymaga skonfigurowania strony internetowej dostępnej w internecie, który będzie ładowany w elemencie iframe. Każdy host sprawdza się w tym przypadku, w tym Hosting Firebase. Utwórz witrynę z taką zawartością:
<!DOCTYPE html> <html> <head> <title>signInWithPopup</title> <script src="signInWithPopup.js"></script> </head> <body><h1>signInWithPopup</h1></body> </html>
Logowanie sfederowane
Jeśli korzystasz z logowania sfederowanego, na przykład przez Google, Apple, SAML lub OIDC, musisz dodać swój identyfikator rozszerzenia Chrome do listy autoryzowanych domeny:
- Otwórz projekt w konsoli Firebase.
- W sekcji Authentication (Uwierzytelnianie) otwórz stronę Settings (Ustawienia).
- Do listy autoryzowanych domen dodaj identyfikator URI podobny do tego:
chrome-extension://CHROME_EXTENSION_ID
W pliku manifestu rozszerzenia do Chrome dodaj te elementy
Adresy URL dodane do listy dozwolonych content_security_policy
:
https://apis.google.com
https://www.gstatic.com
https://www.googleapis.com
https://securetoken.googleapis.com
Wdrażanie uwierzytelniania
W dokumencie HTML signInWithPopup.js to kod JavaScript, który obsługuje uwierzytelnianie. Są 2 sposoby wdrożenia metody, która obsługiwane bezpośrednio w rozszerzeniu:
- Używaj właściwości
firebase/auth
zamiastfirebase/auth/web-extension
. Punkt wejściaweb-extension
dotyczy kodu działającego w rozszerzeniu. Ten kod będzie później uruchamiany w rozszerzeniu (w elemencie iframe, w dokumencie poza ekranem), a kontekstem, w którym się on znajduje, jest standardowa sieć. - Umieść logikę uwierzytelniania w detektorze
postMessage
, aby przesłać żądanie i odpowiedź uwierzytelniania przez serwer proxy.
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) } });
Tworzenie rozszerzenia do Chrome
Gdy witryna będzie już aktywna, możesz z niej korzystać w rozszerzeniu do Chrome.
- Dodaj uprawnienie
offscreen
do pliku manifest.json: - Utwórz dokument poza ekranem. Jest to minimalny plik HTML wewnątrz pakietu rozszerzeń, wczytuje logikę JavaScriptu poza ekranem:
- Dodaj
offscreen.js
do pakietu rozszerzeń. Pełni on funkcję pośrednika między w witrynie publicznej skonfigurowanej w kroku 1 i za pomocą rozszerzenia. - Skonfiguruj dokument poza ekranem z skryptu usługi 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; }
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; }
Teraz, gdy wywołasz firebaseAuth()
w ramach skryptu service worker, zostanie utworzony
otwórz dokument poza ekranem i załaduj witrynę w elemencie iframe. Ten element iframe przetworzy
w tle, a Firebase przejdzie standardowe uwierzytelnianie.
przepływu danych. Po rozwiązaniu lub odrzuceniu obiektu uwierzytelniania
zostanie przesłany z elementu iframe do skryptu service worker za pomocą serwera proxy
dokument.