Xác thực bằng Firebase bằng số điện thoại bằng JavaScript

Bạn có thể sử dụng tính năng Xác thực Firebase để đăng nhập cho người dùng bằng cách gửi tin nhắn SMS đến điện thoại của người dùng đó. Người dùng đăng nhập bằng mã một lần có trong tin nhắn SMS.

Cách dễ dàng nhất để thêm tính năng đăng nhập bằng số điện thoại vào ứng dụng là sử dụng FirebaseUI, bao gồm một tiện ích đăng nhập từ dạng thả xuống giúp triển khai quy trình đăng nhập cho quy trình đăng nhập bằng số điện thoại, cũng như quy trình đăng nhập dựa trên mật khẩu và liên kết. Tài liệu này mô tả cách triển khai quy trình đăng nhập bằng số điện thoại bằng SDK Firebase.

Trước khi bắt đầu

Hãy sao chép đoạn mã khởi động từ bảng điều khiển của Firebase vào dự án của bạn như mô tả trong bài viết Thêm Firebase vào dự án JavaScript nếu bạn chưa thực hiện.

Các mối lo ngại về bảo mật

Việc xác thực chỉ bằng số điện thoại tuy tiện lợi nhưng lại kém an toàn hơn so với các phương thức có sẵn khác vì việc sở hữu số điện thoại có thể dễ dàng được chuyển giữa những người dùng. Ngoài ra, trên các thiết bị có nhiều hồ sơ người dùng, bất kỳ người dùng nào có thể nhận tin nhắn SMS đều có thể đăng nhập vào một tài khoản bằng số điện thoại của thiết bị đó.

Nếu sử dụng tính năng đăng nhập dựa trên số điện thoại trong ứng dụng, bạn nên cung cấp tính năng này cùng với các phương thức đăng nhập an toàn hơn, đồng thời thông báo cho người dùng về một số phương án đánh đổi tính bảo mật khi sử dụng tính năng đăng nhập bằng số điện thoại.

Bật tính năng đăng nhập bằng số điện thoại cho dự án Firebase

Để đăng nhập người dùng bằng SMS, trước tiên, bạn phải bật phương thức đăng nhập bằng Số điện thoại cho dự án Firebase của mình:

  1. Trong bảng điều khiển của Firebase, hãy mở phần Xác thực.
  2. Trên trang Phương thức đăng nhập, hãy bật phương thức đăng nhập Số điện thoại.
  3. Trên cùng trang đó, nếu miền lưu trữ ứng dụng của bạn không được liệt kê trong phần Miền chuyển hướng OAuth, hãy thêm miền của bạn. Lưu ý rằng localhost không được phép làm miền được lưu trữ nhằm mục đích xác thực điện thoại.

Hạn mức yêu cầu đăng nhập bằng số điện thoại của Firebase đủ cao để hầu hết ứng dụng sẽ không bị ảnh hưởng. Tuy nhiên, nếu cần đăng nhập một lượng rất lớn người dùng bằng tính năng xác thực điện thoại, bạn có thể phải nâng cấp gói giá của mình. Xem trang giá.

Thiết lập trình xác minh reCAPTCHA

Trước khi có thể đăng nhập người dùng bằng số điện thoại của họ, bạn phải thiết lập trình xác minh reCAPTCHA của Firebase. Firebase sử dụng reCAPTCHA để ngăn chặn hành vi sai trái, chẳng hạn như bằng cách đảm bảo rằng yêu cầu xác minh số điện thoại đến từ một trong những miền được phép của ứng dụng.

Bạn không cần phải thiết lập ứng dụng reCAPTCHA theo cách thủ công; khi bạn sử dụng đối tượng RecaptchaVerifier của SDK Firebase, Firebase sẽ tự động tạo và xử lý mọi mã bí mật cũng như khoá ứng dụng cần thiết.

Đối tượng RecaptchaVerifier hỗ trợ reCAPTCHA vô hình (reCAPTCHA) thường có thể xác minh người dùng mà không yêu cầu hành động nào của người dùng, cũng như tiện ích reCAPTCHA luôn yêu cầu tương tác của người dùng để hoàn tất thành công.

Có thể bản địa hoá reCAPTCHA cơ bản được kết xuất theo lựa chọn ưu tiên của người dùng bằng cách cập nhật mã ngôn ngữ trên thực thể Xác thực trước khi hiển thị reCAPTCHA. Nội dung bản địa hoá nêu trên cũng sẽ áp dụng cho tin nhắn SMS gửi đến người dùng kèm theo mã xác minh.

Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Sử dụng reCAPTCHA không hiển thị

Để sử dụng reCAPTCHA ẩn, hãy tạo một đối tượng RecaptchaVerifier có tham số size được đặt thành invisible, chỉ định mã nhận dạng của nút gửi biểu mẫu đăng nhập của bạn. Ví dụ:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Sử dụng tiện ích reCAPTCHA

Để sử dụng tiện ích reCAPTCHA hiển thị, hãy tạo một phần tử trên trang của bạn để chứa tiện ích này, sau đó tạo đối tượng RecaptchaVerifier, chỉ định mã nhận dạng của vùng chứa khi bạn làm như vậy. Ví dụ:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

Không bắt buộc: Chỉ định tham số reCAPTCHA

Bạn có thể tuỳ ý đặt hàm callback trên đối tượng RecaptchaVerifier được gọi khi người dùng giải quyết reCAPTCHA hoặc reCAPTCHA hết hạn trước khi người dùng gửi biểu mẫu:

Web

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

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Không bắt buộc: Kết xuất trước reCAPTCHA

Nếu bạn muốn kết xuất trước reCAPTCHA trước khi gửi yêu cầu đăng nhập, hãy gọi render:

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Sau khi render phân giải, bạn sẽ nhận được mã tiện ích của reCAPTCHA mà bạn có thể sử dụng để thực hiện lệnh gọi đến API reCAPTCHA:

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Gửi mã xác minh đến điện thoại của người dùng

Để bắt đầu đăng nhập bằng số điện thoại, hãy hiển thị cho người dùng một giao diện nhắc họ cung cấp số điện thoại, sau đó gọi signInWithPhoneNumber để yêu cầu Firebase gửi mã xác thực đến điện thoại của người dùng qua SMS:

  1. Lấy số điện thoại của người dùng.

    Các yêu cầu pháp lý là khác nhau, nhưng tốt nhất là bạn nên thông báo cho người dùng rằng nếu họ sử dụng tính năng đăng nhập bằng điện thoại, họ có thể nhận được tin nhắn SMS để xác minh và họ sẽ phải trả mức phí tiêu chuẩn.

  2. Gọi signInWithPhoneNumber, truyền vào đó số điện thoại của người dùng và RecaptchaVerifier mà bạn đã tạo trước đó.

    Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    Nếu signInWithPhoneNumber dẫn đến lỗi, hãy đặt lại reCAPTCHA để người dùng có thể thử lại:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });
    

Phương thức signInWithPhoneNumber đưa ra thử thách xác thực reCAPTCHA cho người dùng và nếu người dùng vượt qua thử thách đó, hãy yêu cầu Xác thực Firebase gửi một tin nhắn SMS chứa mã xác minh đến điện thoại của người dùng.

Đăng nhập người dùng bằng mã xác minh

Sau khi lệnh gọi đến signInWithPhoneNumber thành công, hãy nhắc người dùng nhập mã xác minh họ nhận được qua SMS. Sau đó, hãy đăng nhập người dùng bằng cách truyền mã vào phương thức confirm của đối tượng ConfirmationResult đã được truyền đến trình xử lý phương thức thực hiện của signInWithPhoneNumber (tức là khối then của đối tượng). Ví dụ:

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Nếu lệnh gọi đến confirm thành công thì người dùng đã đăng nhập thành công.

Lấy đối tượng AuthCredential trung gian

Nếu bạn cần lấy đối tượng AuthCredential cho tài khoản của người dùng, hãy truyền mã xác minh từ kết quả xác nhận và mã xác minh đến PhoneAuthProvider.credential thay vì gọi confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

Sau đó, bạn có thể đăng nhập người dùng bằng thông tin đăng nhập:

firebase.auth().signInWithCredential(credential);

Kiểm thử bằng số điện thoại ảo

Bạn có thể thiết lập số điện thoại giả định để phát triển thông qua bảng điều khiển của Firebase. Việc kiểm thử bằng số điện thoại giả định mang lại các lợi ích sau:

  • Kiểm thử việc xác thực số điện thoại mà không dùng đến hạn mức sử dụng của bạn.
  • Kiểm tra xác thực số điện thoại mà không cần gửi tin nhắn SMS thực.
  • Chạy các lượt kiểm thử liên tiếp bằng cùng một số điện thoại mà không bị điều tiết. Điều này giúp giảm thiểu nguy cơ bị từ chối trong quá trình xem xét trên Cửa hàng ứng dụng nếu người đánh giá sử dụng cùng một số điện thoại để thử nghiệm.
  • Dễ dàng thử nghiệm trong môi trường phát triển mà không cần tốn thêm công sức, chẳng hạn như khả năng phát triển trong trình mô phỏng iOS hoặc trình mô phỏng Android mà không cần Dịch vụ Google Play.
  • Viết mã kiểm thử tích hợp mà không bị chặn bởi các quy trình kiểm tra bảo mật thường được áp dụng trên số điện thoại thực trong môi trường phát hành chính thức.

Số điện thoại hư cấu phải đáp ứng các yêu cầu sau:

  1. Hãy đảm bảo rằng bạn sử dụng số điện thoại thực sự hư cấu và chưa tồn tại. Xác thực Firebase không cho phép bạn đặt các số điện thoại hiện có mà người dùng thực sử dụng làm số thử nghiệm. Bạn có thể sử dụng 555 số có tiền tố làm số điện thoại thử nghiệm tại Hoa Kỳ. Ví dụ: +1 650-555-3434
  2. Số điện thoại phải được định dạng chính xác về độ dài và các quy tắc ràng buộc khác. Các mã này sẽ vẫn được xác thực giống như số điện thoại của người dùng thực.
  3. Bạn có thể thêm tối đa 10 số điện thoại để phát triển.
  4. Sử dụng các số điện thoại/mã thử nghiệm khó đoán và thường xuyên thay đổi.

Tạo số điện thoại và mã xác minh giả định

  1. Trong bảng điều khiển của Firebase, hãy mở mục Xác thực.
  2. Trong thẻ Phương thức đăng nhập, hãy bật Nhà cung cấp dịch vụ điện thoại nếu bạn chưa bật.
  3. Mở trình đơn chỉnh sửa Số điện thoại để thử nghiệm.
  4. Cung cấp số điện thoại mà bạn muốn kiểm tra, ví dụ: +1 650-555-3434.
  5. Cung cấp mã xác minh gồm 6 chữ số cho số điện thoại cụ thể đó, ví dụ: 654321.
  6. Thêm số điện thoại. Nếu có nhu cầu, bạn có thể xoá số điện thoại và mã số điện thoại đó bằng cách di chuột qua hàng tương ứng rồi nhấp vào biểu tượng thùng rác.

Kiểm thử theo cách thủ công

Bạn có thể trực tiếp bắt đầu sử dụng một số điện thoại giả định trong ứng dụng của mình. Điều này cho phép bạn kiểm thử theo cách thủ công trong các giai đoạn phát triển mà không gặp vấn đề về hạn mức hoặc điều tiết. Bạn cũng có thể kiểm thử trực tiếp từ trình mô phỏng iOS hoặc trình mô phỏng Android mà không cần cài đặt Dịch vụ Google Play.

Khi bạn cung cấp số điện thoại giả định và gửi mã xác minh, sẽ không có tin nhắn SMS thực nào được gửi đi. Thay vào đó, bạn cần cung cấp mã xác minh đã định cấu hình trước đó để hoàn tất quy trình đăng nhập.

Sau khi hoàn tất quá trình đăng nhập, hệ thống sẽ tạo một người dùng Firebase bằng số điện thoại đó. Người dùng này có hành vi và thuộc tính giống như người dùng số điện thoại thực, đồng thời có thể truy cập vào Cơ sở dữ liệu theo thời gian thực/Cloud Firestore cũng như các dịch vụ khác theo cách tương tự. Mã thông báo giá trị nhận dạng được tạo trong quá trình này có cùng chữ ký của người dùng theo số điện thoại thực.

Một lựa chọn khác là đặt vai trò kiểm thử thông qua thông báo xác nhận quyền sở hữu tuỳ chỉnh đối với những người dùng này để phân biệt họ là người dùng giả mạo nếu bạn muốn hạn chế hơn nữa quyền truy cập.

Kiểm thử tích hợp

Ngoài việc kiểm thử thủ công, tính năng Xác thực Firebase còn cung cấp các API để giúp viết chương trình kiểm thử tích hợp để kiểm thử tính năng xác thực điện thoại. Các API này tắt tính năng xác minh ứng dụng bằng cách tắt yêu cầu về reCAPTCHA trong web và thông báo đẩy im lặng trong iOS. Điều này giúp việc kiểm thử tự động hoá có thể diễn ra trong các quy trình này và dễ dàng triển khai hơn. Ngoài ra, các API này còn giúp cung cấp khả năng kiểm thử các quy trình xác minh tức thì trên Android.

Trên web, hãy đặt appVerificationDisabledForTesting thành true trước khi kết xuất firebase.auth.RecaptchaVerifier. Thao tác này sẽ tự động phân giải reCAPTCHA, cho phép bạn truyền số điện thoại mà không cần giải quyết số điện thoại đó theo cách thủ công. Xin lưu ý rằng mặc dù reCAPTCHA đã bị tắt, nhưng bạn vẫn không thể hoàn tất quá trình đăng nhập bằng số điện thoại ảo. Chỉ có thể sử dụng số điện thoại hư cấu với API này.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

Trình xác minh ứng dụng reCAPTCHA mô phỏng và ẩn sẽ hoạt động theo cách khác khi tính năng xác minh ứng dụng bị tắt:

  • reCAPTCHA hiển thị: Khi reCAPTCHA hiển thị được hiển thị qua appVerifier.render(), reCAPTCHA sẽ tự động giải quyết sau độ trễ một phần giây. Điều này tương đương với việc người dùng nhấp vào reCAPTCHA ngay khi kết xuất. Phản hồi reCAPTCHA sẽ hết hạn sau một khoảng thời gian, sau đó sẽ tự động giải quyết lại.
  • reCAPTCHA vô hình: reCAPTCHA vô hình không tự động phân giải khi kết xuất, mà thay vào đó sẽ tự động phân giải trong lệnh gọi appVerifier.verify() hoặc khi nhấp vào nút neo của reCAPTCHA sau một phần nhỏ độ trễ giây. Tương tự, phản hồi sẽ hết hạn sau một khoảng thời gian và sẽ chỉ tự động phân giải sau lệnh gọi appVerifier.verify() hoặc khi người dùng nhấp lại vào nút neo của reCAPTCHA.

Bất cứ khi nào một reCAPTCHA mô phỏng được giải quyết, hàm callback tương ứng sẽ được kích hoạt như dự kiến bằng phản hồi giả mạo. Nếu cũng chỉ định lệnh gọi lại thời hạn, thì lệnh gọi lại này sẽ kích hoạt khi hết hạn.

Các bước tiếp theo

Sau khi người dùng đăng nhập lần đầu, một tài khoản người dùng mới sẽ được tạo và liên kết với thông tin đăng nhập (tức là tên người dùng và mật khẩu, số điện thoại hoặc thông tin nhà cung cấp dịch vụ xác thực) mà người dùng đã đăng nhập. Tài khoản mới này được lưu trữ trong dự án Firebase và có thể dùng để xác định người dùng trên mọi ứng dụng trong dự án của bạn, bất kể người dùng đó đăng nhập bằng cách nào.

  • Trong các ứng dụng, bạn nên đặt đối tượng tiếp nhận dữ liệu trên đối tượng Auth để biết trạng thái xác thực của người dùng. Sau đó, bạn có thể lấy thông tin hồ sơ cơ bản của người dùng từ đối tượng User. Hãy xem phần Quản lý người dùng.

  • Trong Quy tắc bảo mật của Cơ sở dữ liệu theo thời gian thực và Cloud Storage, bạn có thể lấy mã nhận dạng người dùng duy nhất của người dùng đã đăng nhập từ biến auth rồi dùng biến đó để kiểm soát những dữ liệu mà một người dùng có thể truy cập.

Bạn có thể cho phép người dùng đăng nhập vào ứng dụng của mình thông qua nhiều trình cung cấp dịch vụ xác thực bằng cách liên kết thông tin xác thực của nhà cung cấp dịch vụ xác thực với một tài khoản người dùng hiện có.

Để đăng xuất cho một người dùng, hãy gọi signOut:

Web

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

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

Web

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