Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기

Apple 및 C++를 사용하여 인증

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

Firebase SDK를 사용하여 종단 간 OAuth 2.0 로그인 흐름을 수행함으로써 사용자가 Apple ID를 사용하여 Firebase에 인증하도록 할 수 있습니다.

시작하기 전에

Apple을 사용하여 사용자를 로그인하려면 먼저 Apple 개발자 사이트에서 Apple로 로그인을 구성한 다음 Firebase 프로젝트의 로그인 공급자로 Apple을 활성화합니다.

Apple 개발자 프로그램에 참여

Apple로 로그인은 Apple 개발자 프로그램 회원만 구성할 수 있습니다.

Apple로 로그인 구성

Firebase 프로젝트에서 Apple 로그인을 활성화하고 올바르게 구성해야 합니다. 구성은 Android 및 Apple 플랫폼에 따라 다릅니다. 계속하기 전에 Apple 플랫폼 및/또는 Android 가이드의 "Apple로 로그인 구성" 섹션을 따르십시오.

Apple을 로그인 공급자로 활성화

  1. Firebase 콘솔 에서 인증 섹션을 엽니다. 로그인 방법 탭에서 Apple 공급자를 활성화합니다.
  2. Apple 로그인 제공자 설정을 구성합니다.
    1. Apple 플랫폼에만 앱을 배포하는 경우 서비스 ID, Apple 팀 ID, 개인 키 및 키 ID 필드를 비워 둘 수 있습니다.
    2. Android 기기 지원:
      1. Android 프로젝트에 Firebase를 추가합니다 . Firebase 콘솔에서 앱을 설정할 때 앱의 SHA-1 서명을 등록해야 합니다.
      2. Firebase 콘솔 에서 인증 섹션을 엽니다. 로그인 방법 탭에서 Apple 공급자를 활성화합니다. 이전 섹션에서 생성한 서비스 ID를 지정합니다. 또한 OAuth 코드 흐름 구성 섹션에서 Apple 팀 ID와 이전 섹션에서 생성한 개인 키 및 키 ID를 지정합니다.

Apple의 익명 데이터 요구 사항 준수

Apple로 로그인은 사용자가 로그인할 때 이메일 주소를 포함한 데이터를 익명화할 수 있는 옵션을 제공합니다. 이 옵션을 선택한 사용자는 privaterelay.appleid.com 도메인의 이메일 주소를 갖게 됩니다. 앱에서 Apple로 로그인을 사용하는 경우 이러한 익명화된 Apple ID와 관련하여 Apple의 모든 해당 개발자 정책 또는 조건을 준수해야 합니다.

여기에는 직접 식별하는 개인 정보를 익명의 Apple ID와 연결하기 전에 필요한 사용자 동의를 얻는 것이 포함됩니다. Firebase 인증을 사용할 때 여기에는 다음 작업이 포함될 수 있습니다.

  • 이메일 주소를 익명의 Apple ID에 연결하거나 그 반대의 경우도 마찬가지입니다.
  • 전화번호를 익명의 Apple ID에 연결하거나 그 반대로 연결
  • 익명이 아닌 소셜 자격 증명(Facebook, Google 등)을 익명의 Apple ID에 연결하거나 그 반대의 경우도 마찬가지입니다.

위의 목록은 완전하지 않습니다. 앱이 Apple의 요구 사항을 충족하는지 확인하려면 개발자 계정의 멤버십 섹션에 있는 Apple 개발자 프로그램 사용권 계약을 참조하십시오.

firebase::auth::Auth 클래스에 액세스

Auth 클래스는 모든 API 호출의 게이트웨이입니다.
  1. 인증 및 앱 헤더 파일 추가:
    #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::App 에 대한 firebase::auth::Auth 클래스를 가져옵니다. AppAuth 간에 일대일 매핑이 있습니다.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
    

Firebase SDK로 로그인 흐름 처리

Apple로 로그인하는 프로세스는 Apple 및 Android 플랫폼에 따라 다릅니다.

Apple 플랫폼에서

C++ 코드에서 호출된 Apple Sign In Objective-C SDK를 통해 Firebase로 사용자를 인증합니다.

  1. 모든 로그인 요청에 대해 앱의 인증 요청에 대한 응답으로 받은 ID 토큰이 특별히 부여되었는지 확인하는 데 사용할 임의의 문자열("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--;
            }
          }
        }
      }
    
    

    로그인 요청과 함께 nonce의 SHA256 해시를 보내면 Apple이 응답에서 변경하지 않고 전달합니다. Firebase는 원래 nonce를 해시하고 Apple에서 전달한 값과 비교하여 응답을 검증합니다.

  2. 요청에 nonce의 SHA256 해시와 Apple의 응답을 처리할 대리자 클래스를 포함하여 Apple의 로그인 흐름을 시작합니다(다음 단계 참조).

      - (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` 구현에서 Apple의 응답을 처리합니다. 로그인에 성공하면 해시되지 않은 nonce와 함께 Apple 응답의 ID 토큰을 사용하여 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::User*> result =
        auth->SignInWithCredential(credential);
    
  5. 최근 로그인이 필요한 민감한 작업에 대한 새로운 자격 증명을 검색하는 데 사용할 수 있는 Reauthenticate 에 동일한 패턴을 사용할 수 있습니다.

    firebase::Future<firebase::auth::SignInResult> result =
        user->Reauthenticate(credential);
    
  6. 동일한 패턴을 사용하여 계정을 Apple 로그인과 연결할 수 있습니다. 그러나 기존 Firebase 계정이 연결하려는 Apple 계정에 이미 연결되어 있으면 오류가 발생할 수 있습니다. 이것이 발생하면 미래는 SignInResult 상태를 반환하고 kAuthErrorCredentialAlreadyInUse 의 UserInfo 객체는 유효한 updated_credential 을 포함할 수 있습니다. 이 자격 증명은 다른 Apple 로그인 토큰 및 임시 항목을 생성할 필요 없이 SignInWithCredential 을 통해 Apple 연결 계정에 로그인하는 데 사용할 수 있습니다.

    updated_credentialSignInResult.UserInfo 개체의 구성원이므로 자격 증명을 포함하려면 이 작업에 LinkAndRetrieveDataWithCredential 을 사용해야 합니다.

    firebase::Future<firebase::auth::SignInResult> link_result =
        auth->current_user()->LinkAndRetrieveDataWithCredential(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()->info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::User*> result = auth->SignInWithCredential(
          link_result.result()->info.updated_credential);
    } else {
      // Another link error occurred.
    }
    

안드로이드에서

Android에서는 Firebase SDK를 사용하여 웹 기반 일반 OAuth 로그인을 앱에 통합하여 Firebase로 사용자를 인증하여 종단 간 로그인 흐름을 수행합니다.

Firebase SDK로 로그인 흐름을 처리하려면 다음 단계를 따르세요.

  1. Apple에 적합한 제공자 ID로 구성된 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. 선택 사항: Apple의 로그인 화면을 영어 이외의 언어로 표시하려면 locale 매개변수를 설정하십시오. 지원되는 로케일은 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. 인증 제공자 객체를 사용하여 Firebase에 인증합니다. 다른 FirebaseAuth 작업과 달리 사용자가 자격 증명을 입력할 수 있는 웹 보기를 표시하여 UI를 제어합니다.

    로그인 흐름을 시작하려면 signInWithProvider 를 호출하십시오.

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

    그러면 애플리케이션이 Future 에서 콜백을 기다리거나 등록 할 수 있습니다.

  6. 최근 로그인이 필요한 민감한 작업에 대한 새로운 자격 증명을 검색하는 데 사용할 수 있는 ReauthenticateWithProvider 와 동일한 패턴을 사용할 수 있습니다.

    firebase::Future<firebase::auth::SignInResult> result =
      user->ReauthenticateWithProvider(provider_data);
    

    그러면 애플리케이션이 Future 에서 콜백을 기다리거나 등록 할 수 있습니다.

  7. 또한 linkWithCredential() 을 사용하여 다른 ID 공급자를 기존 계정에 연결할 수 있습니다.

    Apple은 사용자의 Apple 계정을 다른 데이터에 연결하기 전에 사용자의 명시적 동의를 요구합니다.

    예를 들어 Facebook 계정을 현재 Firebase 계정에 연결하려면 사용자가 Facebook에 로그인할 때 얻은 액세스 토큰을 사용합니다.

    // 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::SignInResult> result =
        auth.getCurrentUser().linkWithCredential(credential);
    

Apple Notes로 로그인

Firebase 인증에서 지원하는 다른 제공업체와 달리 Apple은 사진 URL을 제공하지 않습니다.

또한 사용자가 이메일을 앱과 공유하지 않기로 선택하면 Apple은 해당 사용자의 고유한 이메일 주소( xyz@privaterelay.appleid.com 형식)를 제공하여 앱과 공유합니다. 개인 이메일 릴레이 서비스를 구성한 경우 Apple은 익명 주소로 전송된 이메일을 사용자의 실제 이메일 주소로 전달합니다.

Apple은 사용자가 처음 로그인할 때만 표시 이름과 같은 사용자 정보를 앱과 공유합니다. 일반적으로 Firebase는 사용자가 Apple에 처음 로그인할 때 표시 이름을 저장하며 getCurrentUser().getDisplayName() 을 사용하여 가져올 수 있습니다. 그러나 이전에 Apple을 사용하여 Firebase를 사용하지 않고 앱에 사용자를 로그인한 경우 Apple은 Firebase에 사용자의 표시 이름을 제공하지 않습니다.

다음 단계

사용자가 처음으로 로그인하면 새 사용자 계정이 생성되어 사용자가 로그인한 자격 증명(사용자 이름 및 암호, 전화 번호 또는 인증 공급자 정보)에 연결됩니다. 이 새 계정은 Firebase 프로젝트의 일부로 저장되며 사용자 로그인 방식에 관계없이 프로젝트의 모든 앱에서 사용자를 식별하는 데 사용할 수 있습니다.

앱에서 Firebase::auth::user 개체에서 사용자의 기본 프로필 정보를 가져올 수 있습니다. 사용자 관리 를 참조하십시오.

Firebase 실시간 데이터베이스 및 Cloud Storage 보안 규칙에서 auth 변수에서 로그인한 사용자의 고유 사용자 ID를 가져와 사용자가 액세스할 수 있는 데이터를 제어하는 ​​데 사용할 수 있습니다.