احراز هویت با استفاده از اپل با جاوا اسکریپت

می‌توانید با استفاده از Firebase SDK برای انجام جریان ورود به سیستم OAuth 2.0 به کاربران خود اجازه دهید با Firebase احراز هویت با استفاده از Apple ID خود انجام دهند.

قبل از اینکه شروع کنی

برای ورود به سیستم کاربرانی که از اپل استفاده می کنند، ابتدا Sign In with Apple را در سایت توسعه دهنده اپل پیکربندی کنید، سپس Apple را به عنوان ارائه دهنده ورود به سیستم برای پروژه Firebase خود فعال کنید.

به برنامه توسعه دهندگان اپل بپیوندید

ورود به سیستم با Apple فقط توسط اعضای برنامه توسعه دهنده Apple قابل پیکربندی است.

پیکربندی ورود با اپل

در سایت Apple Developer موارد زیر را انجام دهید:

  1. همانطور که در بخش اول پیکربندی ورود با اپل برای وب توضیح داده شده است، وب سایت خود را به برنامه خود مرتبط کنید. وقتی از شما خواسته شد، URL زیر را به عنوان URL بازگشتی ثبت کنید:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    می‌توانید ID پروژه Firebase خود را در صفحه تنظیمات کنسول Firebase دریافت کنید.

    وقتی کارتان تمام شد، شناسه سرویس جدید خود را که در بخش بعدی به آن نیاز دارید، یادداشت کنید.

  2. یک ورود به سیستم با کلید خصوصی اپل ایجاد کنید. در بخش بعدی به کلید خصوصی و شناسه کلید جدید خود نیاز دارید.
  3. اگر از یکی از ویژگی‌های Firebase Authentication که برای کاربران ایمیل ارسال می‌کند، از جمله ورود به سیستم پیوند ایمیل، تأیید آدرس ایمیل، لغو تغییر حساب و موارد دیگر، استفاده می‌کنید، سرویس رله ایمیل خصوصی Apple را پیکربندی کنید و noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com را ثبت کنید (یا دامنه قالب ایمیل سفارشی شده شما) تا اپل بتواند ایمیل های ارسال شده توسط Firebase Authentication را به آدرس های ایمیل ناشناس اپل ارسال کند.

اپل را به عنوان ارائه دهنده ورود فعال کنید

  1. Firebase را به پروژه خود اضافه کنید .
  2. در کنسول Firebase ، بخش Auth را باز کنید. در برگه روش ورود ، ارائه دهنده اپل را فعال کنید. شناسه سرویسی که در قسمت قبل ایجاد کردید را مشخص کنید. همچنین در قسمت پیکربندی جریان کد OAuth ، شناسه تیم Apple خود و شناسه کلید خصوصی و کلیدی که در قسمت قبل ایجاد کردید را مشخص کنید.

الزامات داده های ناشناس اپل را رعایت کنید

ورود به سیستم با اپل به کاربران این امکان را می دهد که هنگام ورود به سیستم، داده های خود، از جمله آدرس ایمیل خود را ناشناس نشان دهند. کاربرانی که این گزینه را انتخاب می کنند، آدرس های ایمیل با دامنه privaterelay.appleid.com . هنگامی که از ورود با اپل در برنامه خود استفاده می کنید، باید از هر گونه خط مشی یا شرایط توسعه دهنده قابل اجرا از طرف Apple در مورد این شناسه های ناشناس اپل پیروی کنید.

این شامل اخذ هرگونه رضایت کاربر مورد نیاز قبل از مرتبط کردن هر گونه اطلاعات شخصی شناسایی مستقیم با یک شناسه ناشناس اپل است. هنگام استفاده از Firebase Authentication، این ممکن است شامل اقدامات زیر باشد:

  • یک آدرس ایمیل را به یک Apple ID ناشناس پیوند دهید یا برعکس.
  • یک شماره تلفن را به یک Apple ID ناشناس پیوند دهید یا برعکس
  • یک اعتبار اجتماعی غیر ناشناس (فیس بوک، گوگل و غیره) را به یک شناسه ناشناس اپل پیوند دهید یا بالعکس.

فهرست فوق جامع نیست. به توافقنامه مجوز برنامه توسعه دهنده اپل در بخش عضویت حساب توسعه دهنده خود مراجعه کنید تا مطمئن شوید برنامه شما با الزامات اپل مطابقت دارد.

با Firebase SDK، جریان ورود به سیستم را مدیریت کنید

اگر در حال ساختن یک برنامه وب هستید، ساده‌ترین راه برای احراز هویت کاربران با Firebase با استفاده از حساب‌های Apple آن‌ها، مدیریت کل جریان ورود به سیستم با Firebase JavaScript SDK است.

برای مدیریت جریان ورود به سیستم با Firebase JavaScript SDK، این مراحل را دنبال کنید:

  1. یک نمونه از یک OAuthProvider با استفاده از شناسه ارائه دهنده مربوطه apple.com ایجاد کنید.

    Web version 9

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('apple.com');

    Web version 8

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. اختیاری: دامنه های OAuth 2.0 اضافی را فراتر از پیش فرضی که می خواهید از ارائه دهنده احراز هویت درخواست کنید، مشخص کنید.

    Web version 9

    provider.addScope('email');
    provider.addScope('name');

    Web version 8

    provider.addScope('email');
    provider.addScope('name');

    به‌طور پیش‌فرض، وقتی یک حساب برای هر آدرس ایمیل فعال است، Firebase دامنه ایمیل و نام را درخواست می‌کند. اگر این تنظیم را به چند حساب در هر آدرس ایمیل تغییر دهید، Firebase هیچ محدوده‌ای را از اپل درخواست نمی‌کند مگر اینکه آنها را مشخص کنید.

  3. اختیاری: اگر می خواهید صفحه ورود اپل به زبانی غیر از انگلیسی نمایش داده شود، پارامتر locale را تنظیم کنید. برای مناطق پشتیبانی شده، به اسناد ورود با اپل مراجعه کنید.

    Web version 9

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });

    Web version 8

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. با استفاده از شی ارائه دهنده OAuth با Firebase احراز هویت کنید. می توانید با باز کردن یک پنجره بازشو یا با هدایت مجدد به صفحه ورود، از کاربران خود بخواهید با حساب های اپل خود وارد شوند. روش تغییر مسیر در دستگاه های تلفن همراه ترجیح داده می شود.

    • برای ورود به سیستم با یک پنجره بازشو، signInWithPopup() را فراخوانی کنید:

      Web version 9

      import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
      
      const auth = getAuth();
      signInWithPopup(auth, provider)
        .then((result) => {
          // The signed-in user info.
          const user = result.user;
      
          // Apple credential
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
      
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Web version 8

      firebase
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
      
          // The signed-in user info.
          var user = result.user;
      
          // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
      
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
    • برای ورود به سیستم با تغییر مسیر به صفحه ورود، signInWithRedirect() :

      Web version 9

      import { getAuth, signInWithRedirect } from "firebase/auth";
      
      const auth = getAuth();
      signInWithRedirect(auth, provider);

      Web version 8

      firebase.auth().signInWithRedirect(provider);

      پس از تکمیل ورود کاربر و بازگشت به صفحه، می‌توانید با فراخوانی getRedirectResult() نتیجه ورود را دریافت کنید:

      Web version 9

      import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
      
      // Result from Redirect auth flow.
      const auth = getAuth();
      getRedirectResult(auth)
        .then((result) => {
          const credential = OAuthProvider.credentialFromResult(result);
          if (credential) {
            // You can also get the Apple OAuth Access and ID Tokens.
            const accessToken = credential.accessToken;
            const idToken = credential.idToken;
          }
          // The signed-in user info.
          const user = result.user;
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Web version 8

      // Result from Redirect auth flow.
      firebase
        .auth()
        .getRedirectResult()
        .then((result) => {
          if (result.credential) {
            /** @type {firebase.auth.OAuthCredential} */
            var credential = result.credential;
      
            // You can get the Apple OAuth Access and ID Tokens.
            var accessToken = credential.accessToken;
            var idToken = credential.idToken;
      
            // ...
          }
          // The signed-in user info.
          var user = result.user;
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });

      این نیز جایی است که می توانید خطاها را پیدا کرده و کنترل کنید. برای فهرستی از کدهای خطا، به مرجع API مراجعه کنید.

    برخلاف سایر ارائه دهندگان پشتیبانی شده توسط Firebase Auth، اپل URL عکس ارائه نمی دهد.

    همچنین، وقتی کاربر تصمیم می‌گیرد ایمیل خود را با برنامه به اشتراک نگذارد، اپل یک آدرس ایمیل منحصربه‌فرد برای آن کاربر ارائه می‌کند (به شکل xyz@privaterelay.appleid.com )، که آن را با برنامه شما به اشتراک می‌گذارد. اگر سرویس ارسال ایمیل خصوصی را پیکربندی کرده باشید، اپل ایمیل های ارسال شده به آدرس ناشناس را به آدرس ایمیل واقعی کاربر فوروارد می کند.

    اپل تنها اولین باری که کاربر وارد سیستم می شود، اطلاعات کاربر مانند نام نمایشی را با برنامه ها به اشتراک می گذارد. معمولاً، Firebase نام نمایشی را در اولین باری که کاربر با اپل وارد می شود، ذخیره می کند، که می توانید با firebase.auth().currentUser.displayName با این حال، اگر قبلاً از اپل برای ورود کاربر به برنامه بدون استفاده از Firebase استفاده کرده‌اید، اپل نام نمایشی کاربر را به Firebase ارائه نمی‌کند.

احراز هویت مجدد و پیوند دادن حساب

همین الگو را می توان با reauthenticateWithPopup() و reauthenticateWithRedirect() استفاده کرد، که می توانید از آنها برای بازیابی اعتبار جدید برای عملیات حساسی که نیاز به ورود اخیر دارند استفاده کنید:

Web version 9

import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";

// Result from Redirect auth flow.
const auth = getAuth();
const provider = new OAuthProvider('apple.com');

reauthenticateWithPopup(auth.currentUser, provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    const user = result.user;

    // You can also get the Apple OAuth Access and ID Tokens.
    const credential = OAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    const idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

Web version 8

const provider = new firebase.auth.OAuthProvider('apple.com');

firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.
    /** @type {firebase.auth.OAuthCredential} */
    var credential = result.credential;

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = credential.accessToken;
    var idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

و، می توانید از linkWithPopup() و linkWithRedirect() برای پیوند دادن ارائه دهندگان هویت مختلف به حساب های موجود استفاده کنید.

توجه داشته باشید که اپل از شما می‌خواهد قبل از اینکه حساب‌های اپل آن‌ها را به داده‌های دیگر مرتبط کنید، رضایت صریح را از کاربران دریافت کنید.

به عنوان مثال، برای پیوند دادن یک حساب فیس بوک به حساب فعلی Firebase، از نشانه دسترسی که از ورود کاربر به فیس بوک دریافت کرده اید استفاده کنید:

Web version 9

import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
linkWithPopup(auth.currentUser, provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // ...

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Web version 8

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,

      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

با Firebase در یک برنامه افزودنی Chrome احراز هویت

اگر در حال ساخت یک برنامه افزودنی Chrome هستید، باید شناسه برنامه افزودنی Chrome خود را اضافه کنید:

  1. پروژه خود را در کنسول Firebase باز کنید.
  2. در بخش Authentication ، صفحه روش ورود به سیستم را باز کنید.
  3. یک URI مانند زیر به لیست دامنه های مجاز اضافه کنید:
    chrome-extension://CHROME_EXTENSION_ID

فقط عملیات بازشو ( signInWithPopup ، linkWithPopup ، و reauthenticateWithPopup ) برای برنامه‌های افزودنی Chrome در دسترس است، زیرا برنامه‌های افزودنی Chrome نمی‌توانند از تغییر مسیرهای HTTP استفاده کنند. شما باید این روش‌ها را از یک اسکریپت صفحه پس‌زمینه فراخوانی کنید تا از یک پنجره عملکرد مرورگر، زیرا پنجره بازشو احراز هویت، پنجره عملیات مرورگر را لغو می‌کند. روش‌های بازشو فقط در برنامه‌های افزودنی با استفاده از Manifest V2 قابل استفاده هستند. Manifest V3 جدیدتر فقط به اسکریپت‌های پس‌زمینه در قالب سرویس‌دهندگان اجازه می‌دهد، که اصلاً نمی‌توانند عملیات بازشو را انجام دهند.

در فایل مانیفست افزونه Chrome خود، مطمئن شوید که URL https://apis.google.com را به لیست مجاز content_security_policy اضافه کنید.

توجه داشته باشید که همچنان باید دامنه سفارشی را با اپل به طور مشابه با دامنه پیش فرض firebaseapp.com تأیید کنید:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

پیشرفته: با Firebase در Node.js احراز هویت

برای احراز هویت با Firebase در برنامه Node.js:

  1. کاربر را با حساب اپل خود وارد کنید و رمز اپل آیدی کاربر را دریافت کنید. شما می توانید این کار را به روش های مختلفی انجام دهید. به عنوان مثال، اگر برنامه Node.js شما دارای صفحه نمایش مرورگر است:

    1. در باطن خود، یک رشته تصادفی ("nonce") ایجاد کنید و هش SHA256 آن را محاسبه کنید. nonce یک مقدار استفاده یک بار مصرف است که برای تأیید اعتبار یک رفت و برگشت واحد بین سرورهای باطن و تأیید اعتبار اپل استفاده می کنید.

      Web version 9

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = (length) => {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        let nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      Web version 8

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');
    2. در صفحه ورود به سیستم، nonce هش شده را در پیکربندی Sign In with Apple خود مشخص کنید:

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. رمز Apple ID را از سمت سرور پاسخ تأیید اعتبار POSTed دریافت کنید:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    همچنین به پیکربندی صفحه وب خود برای ورود به سیستم با اپل مراجعه کنید.

  2. پس از دریافت رمز Apple ID کاربر، از آن برای ساختن یک شیء Credential استفاده کنید و سپس کاربر را با اعتبارنامه وارد کنید:

    Web version 9

    import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    
    // Build Firebase credential with the Apple ID token.
    const provider = new OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    signInWithCredential(auth, authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

    Web version 8

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

مراحل بعدی

پس از اینکه کاربر برای اولین بار وارد سیستم شد، یک حساب کاربری جدید ایجاد می‌شود و به اعتبارنامه‌ها (یعنی نام کاربری و رمز عبور، شماره تلفن یا اطلاعات ارائه‌دهنده تاییدیه) مرتبط می‌شود که کاربر با آن وارد شده است. این حساب جدید به‌عنوان بخشی از پروژه Firebase شما ذخیره می‌شود و می‌توان از آن برای شناسایی کاربر در همه برنامه‌های پروژه‌تان، صرف نظر از نحوه ورود کاربر به سیستم استفاده کرد.

  • در برنامه های شما، روش توصیه شده برای اطلاع از وضعیت احراز هویت کاربر، تنظیم ناظر بر روی شی Auth است. سپس می توانید اطلاعات اولیه پروفایل کاربر را از شی User دریافت کنید. به مدیریت کاربران مراجعه کنید.

  • در قوانین امنیتی Firebase Realtime Database و Cloud Storage، می‌توانید شناسه کاربری منحصر به فرد کاربر واردشده به سیستم را از متغیر auth دریافت کنید و از آن برای کنترل داده‌هایی که کاربر می‌تواند به آن دسترسی داشته باشد استفاده کنید.

می‌توانید به کاربران اجازه دهید با استفاده از چندین ارائه‌دهنده احراز هویت، با پیوند دادن اعتبار ارائه‌دهنده تأیید اعتبار به یک حساب کاربری موجود، به برنامه شما وارد شوند.

برای خروج از سیستم کاربر، با خروج از سیستم تماس signOut :

Web version 9

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web version 8

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});