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 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ễ nhất để thêm tính năng đăng nhập bằng số điện thoại vào ứng dụng của bạn là sử dụng FirebaseUI, bao gồm một tiện ích đăng nhập giúp triển khai quy trình đăng nhập bằng số điện thoại, cũng 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 Firebase SDK.

Trước khi bắt đầu

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

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

Mặc dù thuận tiện nhưng việc xác thực chỉ sử dụng số điện thoại sẽ kém an toàn hơn so với các phương thức khác hiện có, vì người dùng có thể dễ dàng chuyển quyền sở hữu số điện thoại. 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 phương thức đă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ề các lợi ích bảo mật khi sử dụng việc đă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 của bạn

Để đă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 bạn:

  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 một 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.

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 không bị ảnh hưởng. Tuy nhiên, nếu cần đăng nhập vào rất nhiều người dùng bằng tính năng xác thực qua điện thoại, thì 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

Để có thể đăng nhập cho 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 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 khoá và thông tin bí mật cần thiết của ứng dụng.

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

Bạn có thể bản địa hoá reCAPTCHA được kết xuất cơ bản sang 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 được gửi đến người dùng, chứa mã xác minh.

API mô-đun 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();

API không gian tên trên web

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

Sử dụng reCAPTCHA vô hình

Để sử dụng reCAPTCHA vô hình, 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ụ:

API mô-đun 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();
  }
});

API không gian tên trên 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 để chứa tiện ích này, sau đó tạo một đối tượng RecaptchaVerifier, trong đó chỉ định mã của vùng chứa khi bạn thực hiện việc này. Ví dụ:

API mô-đun web

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

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

API không gian tên trên 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 reCAPTCHA hoặc reCAPTCHA hết hạn trước khi người dùng gửi biểu mẫu:

API mô-đun 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.
    // ...
  }
});

API không gian tên trên 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:

API mô-đun web

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

API không gian tên trên 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. Bạn có thể dùng mã này để thực hiện lệnh gọi đến API reCAPTCHA:

API mô-đun web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

API không gian tên trên 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 bằng tin nhắn SMS:

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

    Có nhiều yêu cầu pháp lý, nhưng phương pháp hay nhất và để đặt ra kỳ vọng cho người dùng là bạn nên cho người dùng biết 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à mức phí tiêu chuẩn sẽ được áp dụng.

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

    API mô-đun 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
          // ...
        });

    API không gian tên trên 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 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 tính năng 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 mà họ nhận được qua SMS. Sau đó, đă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 này). Ví dụ:

API mô-đun 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?)
  // ...
});

API không gian tên trên 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 tải đối tượng AuthCredential cho tài khoản của người dùng, hãy chuyể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 cho người dùng bằng thông tin đăng nhập:

firebase.auth().signInWithCredential(credential);

Thử nghiệm bằng số điện thoại giả định

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 thử nghiệm bằng số điện thoại hư cấu mang lại những lợi ích sau:

  • Kiểm tra việc xác thực số điện thoại mà không làm tiêu tốn hạn mức sử dụng.
  • 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 thử nghiệm liên tiếp cho cùng một số điện thoại mà không bị điều tiết. Điều này sẽ giúp giảm thiểu nguy cơ bị từ chối trong quá trình đánh giá của Cửa hàng ứng dụng nếu nhân viên đánh giá sử dụng cùng một số điện thoại để kiểm thử.
  • Dễ dàng kiểm thử trong các môi trường phát triển mà không cần làm gì thêm, 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 bước kiểm tra bảo mật thường áp dụng cho 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. Đảm bảo bạn sử dụng số điện thoại thực sự là giả tưởng và chưa tồn tại. Tính năng Xác thực Firebase không cho phép bạn đặt số điện thoại hiện có mà người dùng thực sử dụng làm số thử nghiệm. Một lựa chọn là sử dụng các số có tiền tố 555 làm số điện thoại thử nghiệm ở Hoa Kỳ, ví dụ: +1 650-555-3434
  2. Số điện thoại phải được định dạng chính xác theo độ dài và các hạn chế khác. Chúng vẫn sẽ đượ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. Hãy sử dụng số điện thoại/mã thử nghiệm khó đoán và thay đổi thường xuyên.

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

  1. Trong bảng điều khiển của Firebase, hãy mở phần 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 đàn phong cầm 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. Hãy 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ần, bạn có thể xoá số điện thoại và mã của số điện thoại đó bằng cách di chuột lên 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 hư cấu trong đơn đăng ký của mình. Nhờ đó, bạn có thể kiểm thử thủ công trong các giai đoạn phát triển mà không gặp phải 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ả và gửi mã xác minh, sẽ không có tin nhắn SMS thực nào được gử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 quá trình đăng nhập.

Khi hoàn tất đăng nhập, người dùng Firebase sẽ được tạo bằng số điện thoại đó. Người dùng có hành vi và thuộc tính giống như người dùng số điện thoại thực và 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 mã nhận dạng được tạo trong quá trình này có cùng chữ ký với một người dùng số điện thoại thực.

Một lựa chọn khác là đặt vai trò thử nghiệm 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 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 vô hiệu hoá tính năng xác minh ứng dụng bằng cách tắt yêu cầu reCAPTCHA trong web và thông báo đẩy im lặng trong iOS. Điều này giúp bạn có thể kiểm thử tự động trong các quy trình này và triển khai dễ dàng hơn. Ngoài ra, các API này còn giúp kiểm thử 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 phải giải quyết 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 đăng nhập nếu sử dụng số điện thoại không có thật. Bạn chỉ có thể sử dụng các 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 hiển thị và không hiển thị 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 kết xuất qua appVerifier.render(), reCAPTCHA sẽ tự động tự phân giải sau một phần nhỏ độ trễ của giây. Điều này tương đương với việc người dùng nhấp vào reCAPTCHA ngay sau khi kết xuất. Phản hồi reCAPTCHA sẽ hết hạn sau một khoảng thời gian và sau đó tự động phân giải 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 đó thực hiện như vậy trong lệnh gọi appVerifier.verify()hoặc khi người dùng nhấp vào nút neo của reCAPTCHA sau một phần nhỏ độ trễ của 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 phân giải, 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 bạn cũng chỉ định lệnh gọi lại khi hết hạn, lệnh gọi lại đó 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 tiên, 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 (chẳng hạn như tên người dùng và mật khẩu, số điện thoại hoặc thông tin của 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ữ như một phần trong dự án Firebase và có thể được 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 ứng dụng của bạn, bạn nên đặt trình quan sát 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 Cloud Storage và Cơ sở dữ liệu theo thời gian thực của Firebase, bạn có thể lấy mã nhận dạng người dùng riêng biệt của người dùng đã đăng nhập từ biến auth rồi sử dụng mã này để kiểm soát những dữ liệu mà 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 nhà cung cấp dịch vụ xác thực bằng cách liên kết thông tin đăng nhập 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 một người dùng, hãy gọi signOut:

API mô-đun web

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

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

API không gian tên trên web

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