این سند به شما نشان میدهد که چگونه از Firebase Authentication برای وارد کردن کاربران به یک برنامه افزودنی Chrome استفاده کنید که از Manifest V3 استفاده میکند.
Firebase Authentication چندین روش احراز هویت را برای ورود کاربران از طریق یک برنامه افزودنی Chrome ارائه میکند، که برخی از آنها به تلاش بیشتری نسبت به سایرین نیاز دارند.
برای استفاده از روشهای زیر در افزونه Manifest V3 Chrome، فقط باید آنها را از firebase/auth/web-extension
وارد کنید :
- با ایمیل و رمز عبور وارد شوید (
createUserWithEmailAndPassword
وsignInWithEmailAndPassword
) - با پیوند ایمیل وارد شوید (
sendSignInLinkToEmail
،isSignInWithEmailLink
وsignInWithEmailLink
) - به صورت ناشناس وارد شوید (
signInAnonymously
) - با یک سیستم احراز هویت سفارشی وارد شوید (
signInWithCustomToken
) - ورود ارائه دهنده را به طور مستقل مدیریت کنید سپس از
signInWithCredential
استفاده کنید
روشهای ورود به سیستم زیر نیز پشتیبانی میشوند اما نیاز به کار اضافی دارند:
- با یک پنجره پاپ آپ وارد شوید (
signInWithPopup
،linkWithPopup
، وreauthenticateWithPopup
) - با تغییر مسیر به صفحه ورود به سیستم وارد شوید (
signInWithRedirect
،linkWithRedirect
وreauthenticateWithRedirect
) - با reCAPTCHA با شماره تلفن وارد شوید
- احراز هویت چند عاملی پیامکی با reCAPTCHA
- حفاظت از سازمان reCAPTCHA
برای استفاده از این روشها در افزونه Manifest V3 Chrome، باید از اسناد خارج از صفحه استفاده کنید.
از نقطه ورود firebase/auth/web-extension استفاده کنید
وارد کردن از firebase/auth/web-extension
باعث میشود که کاربران از یک برنامه افزودنی Chrome مشابه یک برنامه وب به سیستم وارد شوند.
firebase/auth/web-extension فقط در نسخههای Web SDK نسخه 10.8.0 و بالاتر پشتیبانی میشود.
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; });
از اسناد خارج از صفحه استفاده کنید
برخی از روشهای احراز هویت، مانند signInWithPopup
، linkWithPopup
، و reauthenticateWithPopup
، مستقیماً با برنامههای افزودنی Chrome سازگار نیستند، زیرا برای بارگیری کد از خارج از بسته برنامه افزودنی نیاز دارند. با شروع در Manifest V3، این کار مجاز نیست و توسط پلتفرم افزونه مسدود خواهد شد. برای دور زدن این موضوع، میتوانید با استفاده از یک سند خارج از صفحه ، آن کد را در یک iframe بارگیری کنید. در سند خارج از صفحه، جریان عادی احراز هویت را اجرا کنید و نتیجه را از سند خارج از صفحه به برنامه افزودنی بازگردانید.
این راهنما از signInWithPopup
به عنوان مثال استفاده می کند، اما همین مفهوم در مورد سایر روش های احراز هویت نیز صدق می کند.
قبل از شروع
این تکنیک از شما میخواهد یک صفحه وب را راهاندازی کنید که در وب در دسترس است و در iframe بارگذاری میکنید. هر میزبانی برای این کار کار می کند، از جمله میزبانی Firebase . یک وب سایت با محتوای زیر ایجاد کنید:
<!DOCTYPE html> <html> <head> <title>signInWithPopup</title> <script src="signInWithPopup.js"></script> </head> <body><h1>signInWithPopup</h1></body> </html>
ورود به سیستم فدرال
اگر از ورود به سیستم فدرال استفاده میکنید، مانند ورود با Google، Apple، SAML، یا OIDC، باید شناسه برنامه افزودنی Chrome خود را به فهرست دامنههای مجاز اضافه کنید:
- پروژه خود را در کنسول Firebase باز کنید.
- در بخش Authentication صفحه تنظیمات را باز کنید.
- یک URI مانند زیر به لیست دامنه های مجاز اضافه کنید:
chrome-extension://CHROME_EXTENSION_ID
در فایل مانیفست افزونه Chrome خود مطمئن شوید که URL های زیر را به لیست مجاز content_security_policy
اضافه کرده اید:
-
https://apis.google.com
-
https://www.gstatic.com
-
https://www.googleapis.com
-
https://securetoken.googleapis.com
اجرای احراز هویت
در سند HTML شما، signInWithPopup.js کد جاوا اسکریپت است که احراز هویت را مدیریت می کند. دو روش مختلف برای پیاده سازی روشی وجود دارد که مستقیماً در افزونه پشتیبانی می شود:
- از
firebase/auth
به جایfirebase/auth/web-extension
استفاده کنید. نقطه ورودweb-extension
برای کدهای در حال اجرا در برنامه افزودنی است. در حالی که این کد در نهایت در برنامه افزودنی اجرا می شود (در iframe، در سند خارج از صفحه شما)، زمینه ای که در آن اجرا می شود، وب استاندارد است. - منطق احراز هویت را در شنونده
postMessage
بپیچید تا درخواست و پاسخ احراز هویت را پراکسی کنید.
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) } });
برنامه افزودنی کروم خود را بسازید
بعد از اینکه وب سایت شما فعال شد، می توانید از آن در برنامه افزودنی Chrome خود استفاده کنید.
- مجوز
offscreen
را به فایل manifest.json خود اضافه کنید: - خود سند خارج از صفحه را ایجاد کنید. این یک فایل حداقلی HTML در بسته برنامه افزودنی شما است که منطق جاوا اسکریپت سند خارج از صفحه شما را بارگیری می کند:
offscreen.js
در بسته برنامه افزودنی خود قرار دهید. به عنوان پروکسی بین وب سایت عمومی راه اندازی شده در مرحله 1 و برنامه افزودنی شما عمل می کند.- سند خارج از صفحه را از کارمند سرویس 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; }
اکنون، وقتی firebaseAuth()
را در سرویسکار خود فرا میخوانید، سند خارج از صفحه را ایجاد میکند و سایت را در یک iframe بارگذاری میکند. آن iframe در پسزمینه پردازش میشود و Firebase از طریق جریان احراز هویت استاندارد عبور میکند. هنگامی که حل شد یا رد شد، شیء احراز هویت با استفاده از سند خارج از صفحه، از iframe شما به سرویسکار شما پراکسی می شود.