เพิ่มการลงชื่อเข้าใช้ไปยังเว็บแอปได้ง่ายๆ ด้วย Firebase UI

FirebaseUI เป็นไลบรารีที่สร้างขึ้นบน Firebase Authentication SDK ซึ่งมีโฟลว์ UI แบบดรอปอินสำหรับใช้ใน แอปของคุณ โดย FirebaseUI มีประโยชน์ดังนี้

  • ผู้ให้บริการหลายราย - โฟลว์การลงชื่อเข้าใช้สำหรับอีเมล/รหัสผ่าน, ลิงก์อีเมล, การตรวจสอบสิทธิ์ทางโทรศัพท์, การลงชื่อเข้าใช้ด้วย Google, Facebook, Twitter และ GitHub
  • การลิงก์บัญชี - โฟลว์สำหรับการลิงก์บัญชีผู้ใช้กับผู้ให้บริการข้อมูลประจำตัวต่างๆ อย่างปลอดภัย
  • การปรับแต่ง - ลบล้างสไตล์ CSS ของ FirebaseUI ให้ตรงกับข้อกำหนดของแอป นอกจากนี้ เนื่องจาก FirebaseUI เป็นโอเพนซอร์ส คุณจึงสามารถ Fork โปรเจ็กต์และปรับแต่งให้ตรงกับความต้องการของคุณได้อย่างแม่นยำ
  • การลงชื่อสมัครใช้ด้วยการแตะครั้งเดียวและการลงชื่อเข้าใช้โดยอัตโนมัติ - การผสานรวมกับ ฟีเจอร์การลงชื่อสมัครใช้ด้วยการแตะครั้งเดียว โดยอัตโนมัติเพื่อการลงชื่อเข้าใช้ข้ามอุปกรณ์ที่รวดเร็ว
  • UI ที่แปลเป็นภาษาท้องถิ่น - การแปลเป็นภาษาต่างๆ มากกว่า 40 ภาษา
  • การอัปเกรดผู้ใช้ที่ไม่ระบุชื่อ - ความสามารถในการอัปเกรดผู้ใช้ที่ไม่ระบุชื่อผ่าน การลงชื่อเข้าใช้/ลงชื่อสมัครใช้ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการอัปเกรดผู้ใช้ที่ไม่ระบุชื่อ

ก่อนเริ่มต้น

  1. เพิ่มการตรวจสอบสิทธิ์ Firebase ลงในเว็บแอปพลิเคชัน โดยตรวจสอบว่าคุณใช้ Namespaced API เวอร์ชัน 9 ขึ้นไป (ไม่ใช่ Modular API) (ดูแถบด้านข้างด้านบน)

  2. รวม FirebaseUI ผ่านตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้

    • CDN

      ใส่สคริปต์และไฟล์ CSS ต่อไปนี้ในแท็ก <head> ของ หน้าเว็บ ใต้ข้อมูลโค้ดเริ่มต้นจาก Firebaseคอนโซล

      <script src="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.js"></script>
      <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css" />
      
    • โมดูล npm

      ติดตั้ง FirebaseUI และทรัพยากร Dependency ผ่าน npm โดยใช้คำสั่งต่อไปนี้

      $ npm install firebaseui --save
      

      require โมดูลต่อไปนี้ภายในไฟล์ต้นทาง

      var firebase = require('firebase');
      var firebaseui = require('firebaseui');
    • คอมโพเนนต์ Bower

      ติดตั้ง FirebaseUI และทรัพยากร Dependency ผ่าน Bower โดยใช้คำสั่งต่อไปนี้

      $ bower install firebaseui --save

      ใส่ไฟล์ที่จำเป็นลงใน HTML หากเซิร์ฟเวอร์ HTTP ให้บริการไฟล์ภายใน bower_components/

      <script src="bower_components/firebaseui/dist/firebaseui.js"></script>
      <link type="text/css" rel="stylesheet" href="bower_components/firebaseui/dist/firebaseui.css" />
      

เริ่มต้น FirebaseUI

หลังจากนำเข้า SDK แล้ว ให้เริ่มต้น UI การตรวจสอบสิทธิ์

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());

ตั้งค่าวิธีการลงชื่อเข้าใช้

คุณต้องเปิดใช้และกำหนดค่าวิธีการลงชื่อเข้าใช้ที่ต้องการรองรับก่อนจึงจะใช้ Firebase เพื่อให้ผู้ใช้ลงชื่อเข้าใช้ได้

อีเมลและรหัสผ่าน

  1. ในคอนโซล Firebase ให้ไปที่ความปลอดภัย > การตรวจสอบสิทธิ์

  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้อีเมล/รหัสผ่าน

  3. เพิ่มรหัสผู้ให้บริการอีเมลลงในรายการ signInOptions ของ FirebaseUI

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        firebase.auth.EmailAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  4. ไม่บังคับ: คุณกำหนดค่า EmailAuthProvider ให้กำหนดให้ผู้ใช้ ป้อนชื่อที่แสดงได้ (ค่าเริ่มต้นคือ true)

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false
        }
      ]
    });
  1. ในคอนโซล Firebase ให้ไปที่ความปลอดภัย > การตรวจสอบสิทธิ์

  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้อีเมล/รหัสผ่าน โปรดทราบว่าคุณต้องเปิดใช้การลงชื่อเข้าใช้ด้วยอีเมล/รหัสผ่านก่อนจึงจะใช้การลงชื่อเข้าใช้ด้วยลิงก์อีเมลได้

  3. ในส่วนเดียวกัน ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ลิงก์อีเมล (ลงชื่อเข้าใช้แบบไม่ต้องใช้รหัสผ่าน)

  4. คลิกบันทึก

  5. เพิ่มรหัสผู้ให้บริการอีเมลลงในรายการ signInOptions ของ FirebaseUI พร้อมกับ signInMethod ของลิงก์อีเมล

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD
        }
      ],
      // Other config options...
    });
  6. เมื่อแสดง UI การลงชื่อเข้าใช้แบบมีเงื่อนไข (เกี่ยวข้องกับแอปหน้าเดียว) ให้ใช้ ui.isPendingRedirect() เพื่อตรวจหาว่า URL ตรงกับการลงชื่อเข้าใช้ด้วยลิงก์อีเมลหรือไม่ และต้องแสดง UI เพื่อให้การลงชื่อเข้าใช้เสร็จสมบูรณ์

    // Is there an email link sign-in?
    if (ui.isPendingRedirect()) {
      ui.start('#firebaseui-auth-container', uiConfig);
    }
    // This can also be done via:
    if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
      ui.start('#firebaseui-auth-container', uiConfig);
    }
  7. ไม่บังคับ: คุณกำหนดค่า EmailAuthProvider สำหรับการลงชื่อเข้าใช้ด้วยลิงก์อีเมลให้ผู้ใช้สามารถหรือบล็อกไม่ให้ผู้ใช้ลงชื่อเข้าใช้ข้ามอุปกรณ์ได้

    คุณกำหนดการเรียกกลับ emailLinkSignIn ที่ไม่บังคับเพื่อแสดงผลการ firebase.auth.ActionCodeSettings ที่จะใช้เมื่อส่งลิงก์ได้ ซึ่งช่วยให้คุณระบุวิธีจัดการลิงก์, Dynamic Link ที่กำหนดเอง, สถานะเพิ่มเติมใน Deep Link ฯลฯ ได้ หากไม่ได้ระบุไว้ ระบบจะใช้ URL ปัจจุบันและทริกเกอร์โฟลว์สำหรับเว็บเท่านั้น

    การลงชื่อเข้าใช้ด้วยลิงก์อีเมลใน FirebaseUI-web ใช้งานร่วมกับ FirebaseUI-Android และ FirebaseUI-iOS ได้ โดยผู้ใช้รายหนึ่งที่เริ่มโฟลว์จาก FirebaseUI-Android จะเปิดลิงก์ และลงชื่อเข้าใช้ด้วย FirebaseUI-web ได้ และในทางกลับกันก็เช่นกัน

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
          signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD,
          // Allow the user the ability to complete sign-in cross device,
          // including the mobile apps specified in the ActionCodeSettings
          // object below.
          forceSameDevice: false,
          // Used to define the optional firebase.auth.ActionCodeSettings if
          // additional state needs to be passed along request and whether to open
          // the link in a mobile app if it is installed.
          emailLinkSignIn: function() {
            return {
              // Additional state showPromo=1234 can be retrieved from URL on
              // sign-in completion in signInSuccess callback by checking
              // window.location.href.
              url: 'https://www.example.com/completeSignIn?showPromo=1234',
              // Custom FDL domain.
              dynamicLinkDomain: 'example.page.link',
              // Always true for email link sign-in.
              handleCodeInApp: true,
              // Whether to handle link in iOS app if installed.
              iOS: {
                bundleId: 'com.example.ios'
              },
              // Whether to handle link in Android app if opened in an Android
              // device.
              android: {
                packageName: 'com.example.android',
                installApp: true,
                minimumVersion: '12'
              }
            };
          }
        }
      ]
    });

ผู้ให้บริการ OAuth (Google, Facebook, Twitter และ GitHub)

  1. ในคอนโซล Firebase ให้ไปที่ความปลอดภัย > การตรวจสอบสิทธิ์

  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้การลงชื่อเข้าใช้ของผู้ให้บริการ OAuth ที่ระบุ ตรวจสอบว่าได้ระบุรหัสไคลเอ็นต์และรหัสลับ OAuth ที่เกี่ยวข้องด้วย

  3. อนุญาตโดเมนของแอปหากยังไม่ได้ดำเนินการ โดยทำดังนี้

    1. ในคอนโซลFirebase ให้ไปที่แท็บ ความปลอดภัย > การตรวจสอบสิทธิ์ > การตั้งค่า

    2. ในส่วนโดเมนที่ได้รับอนุญาต ให้คลิกเพิ่มโดเมน แล้วเพิ่ม โดเมน

  4. เพิ่มรหัสผู้ให้บริการ OAuth ลงในรายการ signInOptions ของ FirebaseUI

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        // List of OAuth providers supported.
        firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        firebase.auth.FacebookAuthProvider.PROVIDER_ID,
        firebase.auth.TwitterAuthProvider.PROVIDER_ID,
        firebase.auth.GithubAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  5. ไม่บังคับ: หากต้องการระบุขอบเขตที่กำหนดเองหรือพารามิเตอร์ OAuth ที่กำหนดเองต่อ ผู้ให้บริการ คุณสามารถส่งออบเจ็กต์แทนค่าผู้ให้บริการได้

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          scopes: [
            'https://www.googleapis.com/auth/contacts.readonly'
          ],
          customParameters: {
            // Forces account selection even when one account
            // is available.
            prompt: 'select_account'
          }
        },
        {
          provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          scopes: [
            'public_profile',
            'email',
            'user_likes',
            'user_friends'
          ],
          customParameters: {
            // Forces password re-entry.
            auth_type: 'reauthenticate'
          }
        },
        firebase.auth.TwitterAuthProvider.PROVIDER_ID, // Twitter does not support scopes.
        firebase.auth.EmailAuthProvider.PROVIDER_ID // Other providers don't need to be given as object.
      ]
    });

หมายเลขโทรศัพท์

  1. ในคอนโซล Firebase ให้ไปที่ความปลอดภัย > การตรวจสอบสิทธิ์

  2. ในแท็บวิธีการลงชื่อเข้าใช้ ให้เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้โทรศัพท์

  3. อนุญาตโดเมนของแอปหากยังไม่ได้ดำเนินการ โดยทำดังนี้

    1. ในคอนโซลFirebase ให้ไปที่แท็บ ความปลอดภัย> การตรวจสอบสิทธิ์ > การตั้งค่า

    2. ในส่วนโดเมนที่ได้รับอนุญาต ให้คลิกเพิ่มโดเมน แล้วเพิ่ม โดเมน

  4. เพิ่มรหัสผู้ให้บริการหมายเลขโทรศัพท์ลงในรายการ signInOptions ของ FirebaseUI

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        firebase.auth.PhoneAuthProvider.PROVIDER_ID
      ],
      // Other config options...
    });
  5. ไม่บังคับ: คุณกำหนดค่า PhoneAuthProvider ด้วยพารามิเตอร์ reCAPTCHA ที่กำหนดเองได้ ไม่ว่า reCAPTCHA จะแสดงหรือไม่ (ค่าเริ่มต้นคือปกติ) ดูรายละเอียดเพิ่มเติมได้ที่ เอกสารประกอบเกี่ยวกับ reCAPTCHA API

    นอกจากนี้ คุณยังตั้งค่าประเทศเริ่มต้นที่จะเลือกในการป้อนหมายเลขโทรศัพท์ได้ด้วย ดูรายการรหัสทั้งหมดได้ที่รายการรหัสประเทศที่รองรับ หากไม่ได้ระบุไว้ การป้อนหมายเลขโทรศัพท์จะมีค่าเริ่มต้นเป็นสหรัฐอเมริกา (+1)

    ปัจจุบันระบบรองรับตัวเลือกต่อไปนี้

    ui.start('#firebaseui-auth-container', {
      signInOptions: [
        {
          provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
          recaptchaParameters: {
            type: 'image', // 'audio'
            size: 'normal', // 'invisible' or 'compact'
            badge: 'bottomleft' //' bottomright' or 'inline' applies to invisible.
          },
          defaultCountry: 'GB', // Set default country to the United Kingdom (+44).
          // For prefilling the national number, set defaultNationNumber.
          // This will only be observed if only phone Auth provider is used since
          // for multiple providers, the NASCAR screen will always render first
          // with a 'sign in with phone number' button.
          defaultNationalNumber: '1234567890',
          // You can also pass the full phone number string instead of the
          // 'defaultCountry' and 'defaultNationalNumber'. However, in this case,
          // the first country ID that matches the country code will be used to
          // populate the country selector. So for countries that share the same
          // country code, the selected country may not be the expected one.
          // In that case, pass the 'defaultCountry' instead to ensure the exact
          // country is selected. The 'defaultCountry' and 'defaultNationaNumber'
          // will always have higher priority than 'loginHint' which will be ignored
          // in their favor. In this case, the default country will be 'GB' even
          // though 'loginHint' specified the country code as '+1'.
          loginHint: '+11234567890'
        }
      ]
    });

ลงชื่อเข้าใช้

หากต้องการเริ่มโฟลว์การลงชื่อเข้าใช้ FirebaseUI ให้เริ่มต้นอินสแตนซ์ FirebaseUI โดยส่งอินสแตนซ์ Auth ที่เกี่ยวข้อง

// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());

กำหนดองค์ประกอบ HTML ที่จะแสดงวิดเจ็ตการลงชื่อเข้าใช้ FirebaseUI

<!-- The surrounding HTML is left untouched by FirebaseUI.
     Your app may use that space for branding, controls and other customizations.-->
<h1>Welcome to My Awesome App</h1>
<div id="firebaseui-auth-container"></div>
<div id="loader">Loading...</div>

ระบุการกำหนดค่า FirebaseUI (ผู้ให้บริการที่รองรับและการปรับแต่ง UI รวมถึงการเรียกกลับเมื่อสำเร็จ เป็นต้น)

var uiConfig = {
  callbacks: {
    signInSuccessWithAuthResult: function(authResult, redirectUrl) {
      // User successfully signed in.
      // Return type determines whether we continue the redirect automatically
      // or whether we leave that to developer to handle.
      return true;
    },
    uiShown: function() {
      // The widget is rendered.
      // Hide the loader.
      document.getElementById('loader').style.display = 'none';
    }
  },
  // Will use popup for IDP Providers sign-in flow instead of the default, redirect.
  signInFlow: 'popup',
  signInSuccessUrl: '<url-to-redirect-to-on-success>',
  signInOptions: [
    // Leave the lines as is for the providers you want to offer your users.
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.FacebookAuthProvider.PROVIDER_ID,
    firebase.auth.TwitterAuthProvider.PROVIDER_ID,
    firebase.auth.GithubAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID,
    firebase.auth.PhoneAuthProvider.PROVIDER_ID
  ],
  // Terms of service url.
  tosUrl: '<your-tos-url>',
  // Privacy policy url.
  privacyPolicyUrl: '<your-privacy-policy-url>'
};

สุดท้าย ให้แสดงอินเทอร์เฟซการตรวจสอบสิทธิ์ FirebaseUI โดยทำดังนี้

// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);

การอัปเกรดผู้ใช้ที่ไม่ระบุชื่อ

การเปิดใช้การอัปเกรดผู้ใช้ที่ไม่ระบุชื่อ

เมื่อผู้ใช้ที่ไม่ระบุชื่อลงชื่อเข้าใช้หรือลงชื่อสมัครใช้ด้วยบัญชีถาวร คุณต้องตรวจสอบว่าผู้ใช้สามารถดำเนินการต่อจากที่ทำไว้ก่อนลงชื่อสมัครใช้ได้ หากต้องการทำเช่นนั้น เพียงตั้งค่า autoUpgradeAnonymousUsers เป็น true เมื่อกำหนดค่า UI การลงชื่อเข้าใช้ (ตัวเลือกนี้จะปิดใช้โดยค่าเริ่มต้น)

การจัดการข้อขัดแย้งในการผสานรวมการอัปเกรดผู้ใช้ที่ไม่ระบุชื่อ

มีบางกรณีที่ผู้ใช้ซึ่งลงชื่อเข้าใช้แบบไม่ระบุชื่อในตอนแรกพยายามอัปเกรดเป็นผู้ใช้ Firebase ที่มีอยู่ เนื่องจากระบบลิงก์ผู้ใช้ที่มีอยู่กับผู้ใช้ที่มีอยู่อีกรายไม่ได้ FirebaseUI จึงจะทริกเกอร์การเรียกกลับ signInFailure พร้อมรหัสข้อผิดพลาด firebaseui/anonymous-upgrade-merge-conflict เมื่อเกิดกรณีดังกล่าว ออบเจ็กต์ข้อผิดพลาดจะมีการรับรองความถูกต้องแบบถาวรด้วย คุณควรทริกเกอร์การลงชื่อเข้าใช้ด้วยข้อมูลเข้าสู่ระบบแบบถาวรในการเรียกกลับเพื่อให้การลงชื่อเข้าใช้เสร็จสมบูรณ์ คุณต้องบันทึกข้อมูลของผู้ใช้ที่ไม่ระบุชื่อและลบผู้ใช้ที่ไม่ระบุชื่อก่อนจึงจะลงชื่อเข้าใช้ผ่าน auth.signInWithCredential(error.credential) ได้ จากนั้นหลังจากลงชื่อเข้าใช้เสร็จแล้ว ให้คัดลอกข้อมูลกลับไปยังผู้ใช้ที่ไม่ระบุชื่อ ตัวอย่างด้านล่างแสดงให้เห็นวิธีการทำงานของโฟลว์นี้

// Temp variable to hold the anonymous user data if needed.
var data = null;
// Hold a reference to the anonymous current user.
var anonymousUser = firebase.auth().currentUser;
ui.start('#firebaseui-auth-container', {
  // Whether to upgrade anonymous users should be explicitly provided.
  // The user must already be signed in anonymously before FirebaseUI is
  // rendered.
  autoUpgradeAnonymousUsers: true,
  signInSuccessUrl: '<url-to-redirect-to-on-success>',
  signInOptions: [
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
    firebase.auth.FacebookAuthProvider.PROVIDER_ID,
    firebase.auth.EmailAuthProvider.PROVIDER_ID,
    firebase.auth.PhoneAuthProvider.PROVIDER_ID
  ],
  callbacks: {
    // signInFailure callback must be provided to handle merge conflicts which
    // occur when an existing credential is linked to an anonymous user.
    signInFailure: function(error) {
      // For merge conflicts, the error.code will be
      // 'firebaseui/anonymous-upgrade-merge-conflict'.
      if (error.code != 'firebaseui/anonymous-upgrade-merge-conflict') {
        return Promise.resolve();
      }
      // The credential the user tried to sign in with.
      var cred = error.credential;
      // Copy data from anonymous user to permanent user and delete anonymous
      // user.
      // ...
      // Finish sign-in after data is copied.
      return firebase.auth().signInWithCredential(cred);
    }
  }
});

ขั้นตอนถัดไป