Xác thực bằng Firebase bằng Tài khoản dựa trên mật khẩu bằng C++

Bạn có thể sử dụng Firebase Authentication để cho phép người dùng xác thực bằng Firebase bằng địa chỉ email và mật khẩu của họ, đồng thời quản lý các tài khoản dựa trên mật khẩu của ứng dụng.

Trước khi bắt đầu

  1. Thêm Firebase vào dự án C++.
  2. Nếu bạn chưa kết nối ứng dụng với dự án Firebase, hãy thực hiện việc này trong bảng điều khiển Firebase.
  3. Bật tính năng đăng nhập bằng email/mật khẩu:
    1. Trong bảng điều khiển Firebase, hãy mở mục Auth (Uỷ quyền).
    2. Trên thẻ Phương thức đăng nhập, hãy bật phương thức đăng nhập Email/mật khẩu rồi nhấp vào Lưu.

Truy cập vào lớp firebase::auth::Auth

Lớp Auth là cổng cho tất cả các lệnh gọi API.
  1. Thêm tệp tiêu đề Auth và App:
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. Trong mã khởi tạo, hãy tạo một lớp firebase::App.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
  3. Lấy lớp firebase::auth::Auth cho firebase::App của bạn. Có mối liên kết một với một giữa AppAuth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

Tạo tài khoản dựa trên mật khẩu

Để tạo tài khoản người dùng mới bằng mật khẩu, hãy hoàn tất các bước sau trong mã đăng nhập của ứng dụng:

  1. Khi người dùng mới đăng ký bằng biểu mẫu đăng ký của ứng dụng, hãy hoàn tất mọi bước xác thực tài khoản mới mà ứng dụng của bạn yêu cầu, chẳng hạn như xác minh rằng mật khẩu của tài khoản mới đã được nhập chính xác và đáp ứng các yêu cầu về độ phức tạp của bạn.
  2. Tạo tài khoản mới bằng cách truyền địa chỉ email và mật khẩu của người dùng mới đến Auth::CreateUserWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPassword(email, password);
  3. Nếu chương trình của bạn có một vòng lặp cập nhật chạy thường xuyên (chẳng hạn như 30 hoặc 60 lần mỗi giây), bạn có thể kiểm tra kết quả một lần cho mỗi lần cập nhật bằng Auth::CreateUserWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Create user succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Created user failed with error '%s'\n", result.error_message());
      }
    }
    Hoặc nếu chương trình của bạn dựa trên sự kiện, bạn có thể muốn đăng ký một lệnh gọi lại trên Future.
.

Đăng nhập người dùng bằng địa chỉ email và mật khẩu

Các bước đăng nhập người dùng bằng mật khẩu tương tự như các bước tạo tài khoản mới. Trong hàm đăng nhập của ứng dụng, hãy làm như sau:

  1. Khi người dùng đăng nhập vào ứng dụng của bạn, hãy truyền địa chỉ email và mật khẩu của người dùng đến firebase::auth::Auth::SignInWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPassword(email, password);
  2. Nếu chương trình của bạn có một vòng lặp cập nhật chạy thường xuyên (chẳng hạn như 30 hoặc 60 lần mỗi giây), bạn có thể kiểm tra kết quả một lần cho mỗi lần cập nhật bằng Auth::SignInWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Sign in succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }
    Hoặc nếu chương trình của bạn dựa trên sự kiện, bạn có thể muốn đăng ký một lệnh gọi lại trên Future.

Đăng ký lệnh gọi lại trên Future

Một số chương trình có các hàm Update được gọi 30 hoặc 60 lần mỗi giây. Ví dụ: nhiều trò chơi tuân theo mô hình này. Các chương trình này có thể gọi các hàm LastResult để thăm dò các lệnh gọi không đồng bộ. Tuy nhiên, nếu chương trình của bạn dựa trên sự kiện, bạn có thể muốn đăng ký các hàm gọi lại. Hàm callback được gọi khi Future hoàn tất.
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
Bạn cũng có thể dùng lambda làm hàm gọi lại nếu muốn.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

Nên làm: Đặt chính sách mật khẩu

Bạn có thể tăng cường độ bảo mật của tài khoản bằng cách thực thi các yêu cầu về độ phức tạp của mật khẩu.

Để định cấu hình chính sách mật khẩu cho dự án của bạn, hãy mở thẻ Chính sách mật khẩu trên trang Cài đặt xác thực của bảng điều khiển Firebase:

Chế độ cài đặt xác thực

Chính sách về mật khẩu Firebase Authentication hỗ trợ các yêu cầu sau đối với mật khẩu:

  • Cần có ký tự viết thường

  • Cần có ký tự viết hoa

  • Bạn phải nhập ký tự số

  • Bắt buộc phải có ký tự không phải chữ và số

    Các ký tự sau đây đáp ứng yêu cầu về ký tự không phải chữ và số: ^ $ * . [ ] { } ( ) ? " ! @ # % & / \ , > < ' : ; | _ ~

  • Độ dài tối thiểu của mật khẩu (từ 6 đến 30 ký tự; mặc định là 6)

  • Độ dài tối đa của mật khẩu (tối đa 4.096 ký tự)

Bạn có thể bật chế độ thực thi chính sách mật khẩu theo hai chế độ:

  • Bắt buộc: Người dùng sẽ không đăng ký được cho đến khi cập nhật mật khẩu tuân thủ chính sách của bạn.

  • Thông báo: Người dùng được phép đăng ký bằng mật khẩu không tuân thủ. Khi sử dụng chế độ này, bạn nên kiểm tra xem mật khẩu của người dùng có tuân thủ chính sách ở phía máy khách hay không và nhắc người dùng cập nhật mật khẩu theo cách nào đó nếu mật khẩu không tuân thủ.

Người dùng mới luôn phải chọn mật khẩu tuân thủ chính sách của bạn.

Nếu có người dùng đang hoạt động, bạn không nên bật tính năng buộc nâng cấp khi đăng nhập, trừ phi bạn dự định chặn quyền truy cập của những người dùng có mật khẩu không tuân thủ chính sách của bạn. Thay vào đó, hãy sử dụng chế độ thông báo. Chế độ này cho phép người dùng đăng nhập bằng mật khẩu hiện tại và thông báo cho họ về những yêu cầu mà mật khẩu của họ chưa đáp ứng.

Đề xuất: Bật tính năng bảo vệ chống liệt kê email

Một số phương thức Firebase Authentication lấy địa chỉ email làm tham số sẽ gửi các lỗi cụ thể nếu địa chỉ email chưa được đăng ký khi phải đăng ký (ví dụ: khi đăng nhập bằng địa chỉ email và mật khẩu) hoặc đã đăng ký khi phải chưa được sử dụng (ví dụ: khi thay đổi địa chỉ email của người dùng). Mặc dù có thể hữu ích trong việc đề xuất các biện pháp khắc phục cụ thể cho người dùng, nhưng tính năng này cũng có thể bị đối tượng xấu lợi dụng để khám phá địa chỉ email mà người dùng của bạn đã đăng ký.

Để giảm thiểu rủi ro này, bạn nên bật tính năng bảo vệ chống liệt kê email cho dự án của mình bằng công cụ gcloud của Google Cloud. Xin lưu ý rằng việc bật tính năng này sẽ thay đổi hành vi báo cáo lỗi của Firebase Authentication: hãy đảm bảo ứng dụng của bạn không dựa vào các lỗi cụ thể 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 (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ụ uỷ quyền) mà người dùng đã đăng nhập. Tài khoản mới này được lưu trữ trong dự án Firebase của bạn và có thể dùng để xác định một người dùng trên mọi ứng dụng trong dự á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 có thể lấy thông tin cơ bản trong hồ sơ của người dùng từ đối tượng firebase::auth::User:

    firebase::auth::User user = auth->current_user();
    if (user.is_valid()) {
      std::string name = user.display_name();
      std::string email = user.email();
      std::string photo_url = user.photo_url();
      // The user's ID, unique to the Firebase project.
      // Do NOT use this value to authenticate with your backend server,
      // if you have one. Use firebase::auth::User::Token() instead.
      std::string uid = user.uid();
    }
  • Trong Firebase Realtime DatabaseCloud Storage Quy tắc bảo mật, 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 và dùng mã nhận dạng này để kiểm soát 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 bạn bằng 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 đăng nhập của trì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 người dùng, hãy gọi SignOut():

auth->SignOut();