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

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

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

برای ورود کاربران با استفاده از اپل، ابتدا ورود با اپل را در سایت توسعه‌دهندگان اپل پیکربندی کنید، سپس اپل را به عنوان ارائه‌دهنده ورود به سیستم برای پروژه Firebase خود فعال کنید.

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

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

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

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

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

  1. در کنسول Firebase ، به بخش امنیت > احراز هویت بروید.
  2. در تب روش ورود ، ارائه‌دهنده‌ی ورود به سیستم اپل را فعال کنید.
  3. تنظیمات ارائه دهنده ورود به سیستم اپل را پیکربندی کنید:
    • اپل : اگر برنامه خود را فقط روی پلتفرم‌های اپل مستقر می‌کنید، می‌توانید فیلدهای شناسه سرویس، شناسه تیم اپل، کلید خصوصی و شناسه کلید را خالی بگذارید.
    • اندروید : برای پشتیبانی از دستگاه‌های اندروید، موارد زیر را تکمیل کنید:
      1. فایربیس را به پروژه اندروید خود اضافه کنید .
      2. اگر قبلاً اثر انگشت SHA-1 برنامه خود را مشخص نکرده‌اید، آن را مشخص کنید.
        1. در کنسول Firebase ، به مسیر زیر بروید: > برگه عمومی .
        2. به پایین صفحه و قسمت «برنامه‌های شما» بروید، برنامه اندروید خود را انتخاب کنید و اثر انگشت SHA-1 خود را در قسمت «اثر انگشت گواهی SHA» اضافه کنید.

        برای جزئیات بیشتر در مورد نحوه دریافت اثر انگشت SHA برنامه خود، به بخش احراز هویت کلاینت خود مراجعه کنید.

      3. تنظیمات ارائه دهنده ورود به سیستم اپل را پیکربندی کنید:
        1. در کنسول Firebase ، به بخش امنیت > احراز هویت بروید.
        2. در برگه «روش ورود» ، روی ارائه‌دهنده ورود به سیستم اپل کلیک کنید.
        3. شناسه سرویس (Service ID) که در قسمت قبل ایجاد کردید را مشخص کنید. همچنین در قسمت پیکربندی جریان کد OAuth، شناسه تیم اپل (Apple Team ID) و کلید خصوصی و شناسه کلید خود را که در قسمت قبل ایجاد کردید، مشخص کنید.

مطابق با الزامات داده‌های ناشناس اپل

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

این شامل دریافت هرگونه رضایت کاربر قبل از مرتبط کردن هرگونه اطلاعات شخصی که مستقیماً هویت شما را مشخص می‌کند با یک Apple ID ناشناس می‌شود. هنگام استفاده از احراز هویت Firebase، این ممکن است شامل اقدامات زیر باشد:

  • یک آدرس ایمیل را به یک 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 را به همراه درخواست ورود خود ارسال خواهید کرد که اپل آن را بدون تغییر در پاسخ ارسال خواهد کرد. فایربیس با هش کردن nonce اصلی و مقایسه آن با مقداری که توسط اپل ارسال شده است، پاسخ را اعتبارسنجی می‌کند.

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

      - (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` خود مدیریت کنید. اگر ورود به سیستم موفقیت‌آمیز بود، از توکن شناسه از پاسخ اپل به همراه nonce هش نشده برای احراز هویت با 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. از رشته توکن حاصل و nonce اصلی برای ساخت یک اعتبارنامه Firebase و ورود به Firebase استفاده کنید.

    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 موجود از قبل به حساب کاربری اپلی که می‌خواهید به آن پیوند دهید پیوند داده شده باشد، با خطایی مواجه شوید. در این صورت، وضعیت kAuthErrorCredentialAlreadyInUse برگردانده می‌شود و AuthResult ممکن است حاوی یک credential معتبر باشد. این اعتبارنامه می‌تواند برای ورود به حساب کاربری پیوند داده شده به اپل از طریق SignInAndRetrieveDataWithCredential بدون نیاز به تولید توکن و nonce دیگری برای 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.
    }

در اندروید

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

برای مدیریت جریان ورود به سیستم با 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 را تنظیم کنید. برای اطلاع از زبان‌های پشتیبانی‌شده، به اسناد Sign In with Apple مراجعه کنید.

    // 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);
    

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

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

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

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

  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);
    

ورود با یادداشت‌های اپل

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

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

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

مراحل بعدی

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

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

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