使用 Apple 和 Unity 进行身份验证

您可以让用户使用其 Apple ID 进行 Firebase 身份验证,方法是使用 Firebase SDK 执行端到端 OAuth 2.0 登录流程。

准备工作

如需让用户能够通过 Apple 帐号登录,首先需在 Apple 的开发者网站上配置“通过 Apple 登录”功能,然后启用 Apple 作为您的 Firebase 项目的登录服务提供方。

加入 Apple Developer Program

“通过 Apple 登录”功能只能由 Apple Developer Program 的成员配置。

配置“通过 Apple 登录”

您必须在 Firebase 项目中启用并正确配置 Apple 登录。Apple Developer 的配置因 Android 和 Apple 平台而异。请先按照 iOS+ 和/或 Android 指南中的“配置‘使用 Apple 帐号登录’功能”部分操作,然后再继续。

启用 Apple 作为登录提供方

  1. Firebase 控制台中,打开 Auth 部分。在登录方法标签页中,启用 Apple 提供方。
  2. 配置 Apple 登录提供方设置:
    1. 如果您仅在 Apple 平台上部署应用,则可以将“服务 ID”“Apple 团队 ID”“私钥和密钥 ID”字段留空。
    2. 对于 Android 设备的支持:
      1. 将 Firebase 添加到您的 Android 项目。当您在 Firebase 控制台中设置应用时,请务必注册应用的 SHA-1 签名。
      2. Firebase 控制台中,打开 Auth 部分。在登录方法标签页中,启用 Apple 提供方。指定您在上一部分中创建的服务 ID。此外,在 OAuth 代码流程配置部分中,指定您的 Apple 团队 ID 以及您在上一部分中创建的私钥和密钥 ID。

符合 Apple 匿名数据要求

如果在登录时选择“通过 Apple 登录”,用户便可对其数据(包括电子邮件地址)进行匿名化处理。选择此选项的用户会拥有使用 privaterelay.appleid.com 网域的电子邮件地址。当您在应用中使用“通过 Apple 登录”时,必须遵守有关这些匿名化 Apple ID 的任何适用的 Apple 开发者政策或条款。

条款内容包括必须首先征得相关用户的同意,才能将能直接识别的个人信息与匿名化的 Apple ID 相关联。使用 Firebase Authentication 时,可能包括以下操作:

  • 将电子邮件地址关联至匿名化的 Apple ID,或者将匿名化的 Apple ID 关联至电子邮件地址。
  • 将电话号码关联至匿名化的 Apple ID,或者将匿名化的 Apple ID 关联至电话号码。
  • 将非匿名社交凭据(Facebook、Google 等)关联至匿名化的 Apple ID,或者将匿名化的 Apple ID 关联至非匿名社交凭据。

以上所列并非全部操作。请参阅您的开发者帐号对应的“成员资格”部分中的“Apple Developer Program 许可协议”,确保您的应用符合 Apple 的要求。

访问 Firebase.Auth.FirebaseAuth

FirebaseAuth 类是所有 API 调用都需要通过的门户,此类可通过 FirebaseAuth.DefaultInstance 访问。
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;

使用 Firebase SDK 处理登录流程

“通过 Apple 登录”的过程因 Apple 和 Android 平台而异。

在 Apple 平台上

  1. 安装第三方插件来处理 Apple 登录 Nonce 和令牌的生成,例如 Unity 的“使用 Apple 帐号登录”资产存储软件包。 您可能需要更改代码,以尝试将生成的 Nonce 随机字符串以原始字符串状态用于 Firebase 操作(具体是指,在创建 SHA256 摘要形式的 Nonce 之前,先存储一份原始 Nonce 的副本)。

  2. 使用生成的令牌字符串和原始 Nonce 构建 Firebase 凭据并登录 Firebase。

    Firebase.Auth.Credential credential =
        Firebase.Auth.OAuthProvider.GetCredential("apple.com", appleIdToken, rawNonce, null);
    auth.SignInAndRetrieveDataWithCredentialAsync(credential).ContinueWith(task => {
      if (task.IsCanceled) {
        Debug.LogError("SignInAndRetrieveDataWithCredentialAsync was canceled.");
        return;
      }
      if (task.IsFaulted) {
        Debug.LogError("SignInAndRetrieveDataWithCredentialAsync encountered an error: " + task.Exception);
        return;
      }
    
      Firebase.Auth.AuthResult result = task.Result;
      Debug.LogFormat("User signed in successfully: {0} ({1})",
          result.User.DisplayName, result.User.UserId);
    });
    

  3. 上述模式同样适用于 ReauthenticateAsync,它可用来为要求用户必须有近期登录才能执行的敏感操作检索新的凭据。如需了解详情,请参阅管理用户

  4. 如果已有 Firebase 帐号与 Apple 帐号相关联,那么当您在 Apple 平台上关联 Apple 登录时可能会遇到错误。发生这种情况时,系统将抛出 Firebase.Auth.FirebaseAccountLinkException,而不是标准的 Firebase.FirebaseException。在这种情况下,例外包括 UserInfo.UpdatedCredential 属性,如果该属性有效,您可以使用它通过 FirebaseAuth.SignInAndRetrieveDataWithCredentialAsync 登录与 Apple 关联的用户帐号。有了更新后的凭据,便无需再为登录操作生成新的 Apple 登录令牌和 Nonce。

    auth.CurrentUser.LinkWithCredentialAsync(
      Firebase.Auth.OAuthProvider.GetCredential("apple.com", idToken, rawNonce, null))
        .ContinueWithOnMainThread( task => {
          if (task.IsCompletedSuccessfully) {
            // Link Success
          } else {
            if (task.Exception != null) {
              foreach (Exception exception in task.Exception.Flatten().InnerExceptions) {
                Firebase.Auth.FirebaseAccountLinkException firebaseEx =
                  exception as Firebase.Auth.FirebaseAccountLinkException;
                if (firebaseEx != null && firebaseEx.UserInfo.UpdatedCredential.IsValid()) {
                  // Attempt to sign in with the updated credential.
                  auth.SignInAndRetrieveDataWithCredentialAsync(firebaseEx.UserInfo.UpdatedCredential).
                    ContinueWithOnMainThread( authResultTask => {
                      // Handle Auth result.
                    });
                } else {
                  Debug.Log("Link with Apple failed:" + firebaseEx );
                }
              } // end for loop
            }
          }
        });
    

Android 设备

在 Android 上,您可以使用 Firebase SDK 将基于 Web 的通用 OAuth 登录机制集成到您的应用中来执行端到端登录流程,从而对用户进行 Firebase 身份验证。

如需使用 Firebase SDK 处理登录流程,请按以下步骤操作:

  1. 构建一个配置了适用于 Apple 的提供方 ID 的 FederatedOAuthProviderData 实例。

    Firebase.Auth.FederatedOAuthProviderData providerData =
      new Firebase.Auth.FederatedOAuthProviderData();
    
    providerData.ProviderId = "apple.com";
    
  2. 可选:指定您希望向身份验证提供方申请的超出默认范围的额外 OAuth 2.0 范围。

    providerData.Scopes = new List<string>();
    providerData.Scopes.Add("email");
    providerData.Scopes.Add("name");
    
  3. 可选:如果想要以英文以外的语言显示 Apple 的登录屏幕,请设置 locale 参数。如需了解受支持的语言区域,请查看“通过 Apple 登录”文档

    providerData.CustomParameters = new Dictionary<string,string>;
    
    // Localize to French.
    providerData.CustomParameters.Add("language", "fr");
    
  4. 提供方数据配置完成后,使用它来创建 FederatedOAuthProvider。

    // Construct a FederatedOAuthProvider for use in Auth methods.
    Firebase.Auth.FederatedOAuthProvider provider =
      new Firebase.Auth.FederatedOAuthProvider();
    provider.SetProviderData(providerData);
    
  5. 使用 Auth 提供方对象进行 Firebase 身份验证。请注意,与其他 FirebaseAuth 操作不同,此操作会弹出可供用户输入其凭据的网页视图,从而控制您的界面。

    如需启动登录流程,请调用 signInWithProvider

    auth.SignInWithProviderAsync(provider).ContinueOnMainThread(task => {
        if (task.IsCanceled) {
            Debug.LogError("SignInWithProviderAsync was canceled.");
            return;
        }
        if (task.IsFaulted) {
            Debug.LogError("SignInWithProviderAsync encountered an error: " +
              task.Exception);
            return;
        }
    
        Firebase.Auth.AuthResult authResult = task.Result;
        Firebase.Auth.FirebaseUser user = authResult.User;
        Debug.LogFormat("User signed in successfully: {0} ({1})",
            user.DisplayName, user.UserId);
    });
    
  6. 上述模式同样适用于 ReauthenticateWithProvider,它可用来为要求用户必须有近期登录才能执行的敏感操作检索新的凭据。

    user.ReauthenticateWithProviderAsync(provider).ContinueOnMainThread(task => {
        if (task.IsCanceled) {
            Debug.LogError("ReauthenticateWithProviderAsync was canceled.");
            return;
        }
        if (task.IsFaulted) {
            Debug.LogError(
            "ReauthenticateWithProviderAsync encountered an error: " +
                task.Exception);
            return;
        }
    
        Firebase.Auth.AuthResult authResult = task.Result;
        Firebase.Auth.FirebaseUser user = authResult.User;
        Debug.LogFormat("User reauthenticated successfully: {0} ({1})",
            user.DisplayName, user.UserId);
    });
    
  7. 此外,您可以使用 LinkWithCredentialAsync() 将不同的身份提供方关联至现有帐号。

    请注意,Apple 要求您须征得用户的明确同意,才能将用户的 Apple 帐号关联至其他数据。

    例如,如需将 Facebook 帐号关联至当前的 Firebase 帐号,请使用将用户登录到 Facebook 时获得的访问令牌:

    // Initialize a Facebook credential with a Facebook access token.
    
    Firebase.Auth.Credential credential =
        Firebase.Auth.FacebookAuthProvider.GetCredential(facebook_token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    user.LinkWithCredentialAsync(credential)
        .ContinueWithOnMainThread( task => {
          if (task.IsCanceled) {
              Debug.LogError("LinkWithCredentialAsync was canceled.");
              return;
          }
          if (task.IsFaulted) {
            Debug.LogError("LinkWithCredentialAsync encountered an error: "
                           + task.Exception);
              return;
          }
    
          Firebase.Auth.AuthResult result = task.Result;
          Firebase.Auth.FirebaseUser user = result.User;
          Debug.LogFormat("User linked successfully: {0} ({1})",
              user.DisplayName, user.UserId);
        });
    

使用 Apple Notes 登录

与 Firebase Authentication 支持的其他提供方不同,Apple 不提供照片网址。

此外,当用户选择不与应用共享其电子邮件时,Apple 会为该用户分配一个格式为 xyz@privaterelay.appleid.com 的唯一电子邮件地址并与应用共享该地址。如果您配置了私人电子邮件中继服务,则 Apple 会将发送到匿名化地址的电子邮件转发到用户的真实电子邮件地址。

Apple 只会在用户首次登录时与应用共享用户信息(例如显示名)。Firebase 通常会在用户首次使用 Apple 帐号登录时存储显示名,您可以使用 auth.CurrentUser.DisplayName 获取该显示名。不过,如果您过去曾在未使用 Firebase 的情况下已通过 Apple 帐号将用户登录到应用,则 Apple 不会向 Firebase 提供该用户的显示名。

后续步骤

在用户首次登录后,系统会创建一个新的用户帐号,并将其与该用户登录时使用的凭据(即用户名和密码、电话号码或者身份验证提供方信息)相关联。此新帐号存储在您的 Firebase 项目中,无论用户采用何种方式登录,您项目中的每个应用都可以使用此帐号来识别用户。

在您的应用中,您可以从 Firebase.Auth.FirebaseUser 对象获取用户的个人资料基本信息。请参阅管理用户

在您的 Firebase Realtime Database 和 Cloud Storage 安全规则中,您可以从 auth 变量中获取已登录用户的唯一用户 ID,然后用此 ID 来控制用户可以访问哪些数据。