با استفاده از Apple و C++ احراز هویت

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

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

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

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

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

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

Apple Sign In باید در پروژه Firebase شما فعال و به درستی پیکربندی شود. پیکربندی در پلتفرم های اندروید و اپل متفاوت است. لطفاً قبل از ادامه، بخش «پیکربندی ورود به سیستم با اپل» را در پلتفرم‌های اپل و/یا راهنمای Android دنبال کنید.

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

  1. در کنسول Firebase ، بخش Auth را باز کنید. در زبانه روش ورود ، ارائه دهنده اپل را فعال کنید.
  2. تنظیمات ارائه دهنده Apple Sign-in را پیکربندی کنید:
    1. اگر برنامه خود را فقط بر روی پلتفرم‌های اپل اجرا می‌کنید، می‌توانید قسمت‌های شناسه سرویس، شناسه تیم اپل، کلید خصوصی و شناسه کلید را خالی بگذارید.
    2. برای پشتیبانی در دستگاه های اندروید:
      1. Firebase را به پروژه اندروید خود اضافه کنید . هنگام تنظیم برنامه خود در کنسول Firebase، حتماً امضای SHA-1 برنامه خود را ثبت کنید.
      2. در کنسول Firebase ، بخش Auth را باز کنید. در زبانه روش ورود ، ارائه دهنده اپل را فعال کنید. شناسه سرویسی که در قسمت قبل ایجاد کردید را مشخص کنید. همچنین در قسمت OAuth code flow configuration، Apple Team ID و شناسه کلید خصوصی و کلیدی که در قسمت قبل ایجاد کردید را مشخص کنید.

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

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

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

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

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

دسترسی به firebase::auth::Auth

کلاس Auth دروازه همه تماس‌های API است.
  1. فایل‌های هدر Auth و App را اضافه کنید:
    #include "firebase/app.h"
    #include "firebase/auth.h"
    
  2. در کد اولیه خود، یک کلاس 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. firebase::auth::Auth را برای firebase::App خود دریافت کنید. یک نگاشت یک به یک بین App و Auth وجود دارد.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
    

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

فرآیند ورود به سیستم با اپل در پلتفرم های اپل و اندروید متفاوت است.

در پلتفرم های اپل

کاربران خود را با Firebase از طریق Apple Sign In Objective-C SDK که از کد C++ شما فراخوانی شده است، احراز هویت کنید.

  1. برای هر درخواست ورود به سیستم، یک رشته تصادفی ایجاد کنید - یک "nonce" - که از آن استفاده می کنید تا مطمئن شوید که رمز شناسه دریافتی به طور خاص در پاسخ به درخواست احراز هویت برنامه شما اعطا شده است. این مرحله برای جلوگیری از حملات تکراری مهم است.

      - (NSString *)randomNonce:(NSInteger)length {
        NSAssert(length > 0, @"Expected nonce to have positive length");
        NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
        NSMutableString *result = [NSMutableString string];
        NSInteger remainingLength = length;
    
        while (remainingLength > 0) {
          NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
          for (NSInteger i = 0; i < 16; i++) {
            uint8_t random = 0;
            int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
            NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode);
    
            [randoms addObject:@(random)];
          }
    
          for (NSNumber *random in randoms) {
            if (remainingLength == 0) {
              break;
            }
    
            if (random.unsignedIntValue < characterSet.length) {
              unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
              [result appendFormat:@"%C", character];
              remainingLength--;
            }
          }
        }
      }
    
    

    شما هش SHA256 nonce را همراه با درخواست ورود خود ارسال می‌کنید که اپل در پاسخ آن را بدون تغییر ارسال می‌کند. Firebase پاسخ را با هش کردن nonce اصلی و مقایسه آن با مقدار ارسال شده توسط Apple تأیید می کند.

  2. جریان ورود به سیستم اپل را شروع کنید، از جمله در درخواست خود هش SHA256 از nonce و کلاس نماینده که پاسخ اپل را مدیریت می کند (مرحله بعدی را ببینید):

      - (void)startSignInWithAppleFlow {
        NSString *nonce = [self randomNonce:32];
        self.currentNonce = nonce;
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];
        request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        request.nonce = [self stringBySha256HashingString:nonce];
    
        ASAuthorizationController *authorizationController =
            [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
        authorizationController.delegate = self;
        authorizationController.presentationContextProvider = self;
        [authorizationController performRequests];
      }
    
      - (NSString *)stringBySha256HashingString:(NSString *)input {
        const char *string = [input UTF8String];
        unsigned char result[CC_SHA256_DIGEST_LENGTH];
        CC_SHA256(string, (CC_LONG)strlen(string), result);
    
        NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
        for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
          [hashed appendFormat:@"%02x", result[i]];
        }
        return hashed;
      }
    
  3. در اجرای ASAuthorizationControllerDelegate به پاسخ اپل رسیدگی کنید. اگر ورود به سیستم موفقیت آمیز بود، برای احراز هویت با Firebase، از کد شناسه پاسخ اپل با نون هش نشده استفاده کنید:

      - (void)authorizationController:(ASAuthorizationController *)controller
         didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
        if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
          ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
          NSString *rawNonce = self.currentNonce;
          NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent.");
    
          if (appleIDCredential.identityToken == nil) {
            NSLog(@"Unable to fetch identity token.");
            return;
          }
    
          NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken
                                                    encoding:NSUTF8StringEncoding];
          if (idToken == nil) {
            NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken);
          }
        }
    
  4. برای ساختن اعتبار Firebase و ورود به Firebase از رشته توکن به دست آمده و nonce اصلی استفاده کنید.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. همین الگو را می توان با Reauthenticate استفاده کرد که می تواند برای بازیابی اعتبارنامه های جدید برای عملیات حساسی که نیاز به ورود اخیر دارند استفاده شود.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. از همین الگو می توان برای پیوند دادن یک حساب با Apple Sign In استفاده کرد. با این حال، ممکن است زمانی که یک حساب Firebase موجود قبلاً به حساب Apple که می‌خواهید با آن پیوند برقرار کنید، با خطا روبرو شوید. هنگامی که این اتفاق می افتد، آینده وضعیت kAuthErrorCredentialAlreadyInUse را برمی گرداند و AuthResult ممکن است حاوی یک credential معتبر باشد. این اعتبارنامه را می توان برای ورود به حساب مرتبط با Apple از طریق SignInAndRetrieveDataWithCredential بدون نیاز به ایجاد توکن و غیره Apple Sign In دیگر استفاده کرد.

    firebase::Future<firebase::auth::AuthResult> link_result =
        auth->current_user().LinkWithCredential(credential);
    
    // To keep example simple, wait on the current thread until call completes.
    while (link_result.status() == firebase::kFutureStatusPending) {
      Wait(100);
    }
    
    // Determine the result of the link attempt
    if (link_result.error() == firebase::auth::kAuthErrorNone) {
      // user linked correctly.
    } else if (link_result.error() ==
                   firebase::auth::kAuthErrorCredentialAlreadyInUse &&
               link_result.result()
                   ->additional_user_info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::AuthResult> result =
          auth->SignInAndRetrieveDataWithCredential(
              link_result.result()->additional_user_info.updated_credential);
    } else {
      // Another link error occurred.
    }
    

در اندروید

در Android، کاربران خود را با Firebase با ادغام ورود به سیستم OAuth عمومی مبتنی بر وب در برنامه خود با استفاده از Firebase SDK برای انجام جریان ورود به سیستم از انتها به سیستم، احراز هویت کنید.

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

  1. یک نمونه از FederatedOAuthProviderData پیکربندی شده با شناسه ارائه دهنده مناسب برای اپل بسازید.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. اختیاری: محدوده های OAuth 2.0 اضافی را فراتر از پیش فرضی که می خواهید از ارائه دهنده احراز هویت درخواست کنید، مشخص کنید.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. اختیاری: اگر می خواهید صفحه ورود اپل به زبانی غیر از انگلیسی نمایش داده شود، پارامتر locale را تنظیم کنید. برای مناطق پشتیبانی شده، به اسناد ورود با اپل مراجعه کنید.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. هنگامی که داده های ارائه دهنده شما پیکربندی شد، از آن برای ایجاد یک FederatedOAuthProvider استفاده کنید.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. با استفاده از شی ارائه دهنده Auth با Firebase احراز هویت کنید. توجه داشته باشید که برخلاف سایر عملیات FirebaseAuth، این کار با نمایش یک نمای وب که در آن کاربر می‌تواند اعتبار خود را وارد کند، رابط کاربری شما را کنترل می‌کند.

    برای شروع جریان ورود به سیستم، signInWithProvider فراخوانی کنید:

    firebase::Future<firebase::auth::AuthResult> result =
      auth->SignInWithProvider(provider_data);
    

    سپس درخواست شما ممکن است منتظر بماند یا در Future یک تماس برگشتی ثبت کند .

  6. همین الگو را می توان با ReauthenticateWithProvider استفاده کرد که می تواند برای بازیابی اعتبارنامه های جدید برای عملیات حساسی که نیاز به ورود اخیر دارند استفاده شود.

    firebase::Future<firebase::auth::AuthResult> result =
      user.ReauthenticateWithProvider(provider_data);
    

    سپس درخواست شما ممکن است منتظر بماند یا در Future یک تماس برگشتی ثبت کند .

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

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

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

    // Initialize a Facebook credential with a Facebook access token.
    AuthCredential credential =
        firebase::auth::FacebookAuthProvider.getCredential(token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    firebase::Future<firebase::auth::AuthResult> result =
        auth.current_user().LinkWithCredential(credential);
    

با Apple Notes وارد شوید

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

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

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

مراحل بعدی

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

در برنامه های خود، می توانید اطلاعات اولیه پروفایل کاربر را از firebase::auth::User object دریافت کنید. به مدیریت کاربران مراجعه کنید.

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