【问题标题】:how to save firebase auth between scenes如何在场景之间保存firebase身份验证
【发布时间】:2020-10-02 12:36:06
【问题描述】:

大家好,我是 Unity 和 C# 的新手。 我有这个脚本来创建/登录用户并在 firebase 数据库中发布(使用电子邮件和密码)。 我从 youtube 教程中复制了它,做了一些修改

using System.Collections;
using System.Collections.Generic;
using FullSerializer;
using Proyecto26;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using Firebase.Auth;

public class PlayerScores : MonoBehaviour
{
    public Text scoreText;
    public InputField getScoreText;

    public InputField emailText;
    public InputField usernameText;
    public InputField passwordText;

    private System.Random random = new System.Random();

    User user = new User();

    private string databaseURL = "testingurl";
    private string AuthKey = "testingapikey";

    public static fsSerializer serializer = new fsSerializer();


    public static int playerScore;
    public static string playerName;

    private string idToken;

    public static string localId;

    private string getLocalId;


    private void Start()
    {
        playerScore = random.Next(0, 101);
        scoreText.text = "Score: " + playerScore;
    }

    public void OnSubmit()
    {
        PostToDatabase();
        Debug.Log("datos subidos a database");
    }

    public void OnGetScore()
    {
        GetLocalId();
    }

    private void UpdateScore()
    {
        scoreText.text = "Score: " + user.userScore;
    }

    private void PostToDatabase(bool emptyScore = false, string idTokenTemp = "")
    {
        if (idTokenTemp == "")
        {
            idTokenTemp = idToken;
        }

        User user = new User();

        if (emptyScore)
        {
            user.userScore = 0;
        }

        RestClient.Put(databaseURL + "/" + localId + ".json?auth=" + idTokenTemp, user);
    }

    private void RetrieveFromDatabase()
    {
        RestClient.Get<User>(databaseURL + "/" + getLocalId + ".json?auth=" + idToken).Then(response =>
        {
            user = response;
            UpdateScore();
        });
    }

    public void SignUpUserButton()
    {
        SignUpUser(emailText.text, usernameText.text, passwordText.text);
    }

    public void SignInUserButton()
    {
        SignInUser(emailText.text, passwordText.text);

    }

    private void SignUpUser(string email, string username, string password)
    {
        string userData = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\",\"returnSecureToken\":true}";
        RestClient.Post<SignResponse>("https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=" + AuthKey, userData).Then(
            response =>
            {
                string emailVerification = "{\"requestType\":\"VERIFY_EMAIL\",\"idToken\":\"" + response.idToken + "\"}";
                RestClient.Post(
                    "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key=" + AuthKey,
                    emailVerification);
                localId = response.localId;
                playerName = username;
                PostToDatabase(true, response.idToken);
                Debug.Log("SingUp Correcto");

            }).Catch(error =>
            {
                Debug.Log("falta email/password");
                Debug.Log(error);
            });
    }

    private void SignInUser(string email, string password)
    {
        string userData = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\",\"returnSecureToken\":true}";
        RestClient.Post<SignResponse>("https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=" + AuthKey, userData).Then(
            response =>
            {
                string emailVerification = "{\"idToken\":\"" + response.idToken + "\"}";
                RestClient.Post(
                    "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=" + AuthKey,
                    emailVerification).Then(
                    emailResponse =>
                    {

                        fsData emailVerificationData = fsJsonParser.Parse(emailResponse.Text);
                        EmailConfirmationInfo emailConfirmationInfo = new EmailConfirmationInfo();
                        serializer.TryDeserialize(emailVerificationData, ref emailConfirmationInfo).AssertSuccessWithoutWarnings();

                        if (emailConfirmationInfo.users[0].emailVerified)
                        {
                            idToken = response.idToken;
                            localId = response.localId;
                            GetUsername();
                            Debug.Log("Login Correcto");
                            SceneManager.LoadScene("SignInEdit"); //para logear correctamente solo necesita que el email y password sean correctos, el username no importa.
                        }
                        else
                        {
                            Debug.Log("You are stupid, you need to verify your email dumb");
                        }
                    });

            }).Catch(error =>
            {
                Debug.Log(error);
            });
    }

    private void GetUsername()
    {
        RestClient.Get<User>(databaseURL + "/" + localId + ".json?auth=" + idToken).Then(response =>
        {
            playerName = response.userName;
        });
    }

    private void GetLocalId()
    {
        RestClient.Get(databaseURL + ".json?auth=" + idToken).Then(response =>
        {
            var username = getScoreText.text;

            fsData userData = fsJsonParser.Parse(response.Text);
            Dictionary<string, User> users = null;
            serializer.TryDeserialize(userData, ref users);

            foreach (var user in users.Values)
            {
                if (user.userName == username)
                {
                    getLocalId = user.localId;
                    RetrieveFromDatabase();
                    break;
                }
            }
        }).Catch(error =>
        {
            Debug.Log(error);
        });
    }
}

我的问题是我无法在场景之间保存我的 firebase 登录信息,当我更改场景时,我无法再与我的 firebase 数据库进行交互。 我尝试制作一个 dontdestroyonload 脚本并添加一个统一游戏对象,其中包含我的 PlayerScore 脚本,但没有奏效。

我读到我需要将我的用户 ID 存储在一个静态变量中以便从任何地方调用它,但我不知道如何,因为我对 c# 编码非常陌生

有人可以指导一下吗,谢谢。 PS:上面的脚本需要另外 3 个脚本才能工作,其中存储/获取一些值。 如果有必要,我会添加它们。

【问题讨论】:

    标签: c# firebase unity3d firebase-authentication


    【解决方案1】:

    我认为这里可能存在一些混淆,因为我看到 official Firebase Unity SDK 的引用与 RestClient 中的原始 REST 调用混合在一起。假设您可以使用Unity SDK,我会回答这个问题。与尝试手动使用 Firebase SDK 相比,这是一个更简单的集成(并为您带来了不错的好处 - 例如本地缓存)。

    1) Firebase 身份验证

    初始化 Firebase 身份验证后,FirebaseAuth.DefaultInstance.CurrentUser 将始终包含您当前登录的用户,如果用户未登录,则 null。此值实际上存储在 C++ 中并通过 C# 访问,这意味着它不会实际上了解或遵守 Unity 的典型对象生命周期。这意味着一旦您登录了用户,此值将始终保留当前用户,而无需跨越场景边界将其保留。事实上,这个值甚至会在您的游戏运行过程中保留下来(这意味着您的玩家不必每次都登录)。

    对此有一个警告:CurrentUser 是异步更新的——也就是说,不能真正保证CurrentUser 是最新的——所以注册一个StateChanged 监听器通常是安全的,正如 Puf 建议的@ 987654324@:

    Firebase.Auth.FirebaseAuth auth;
    Firebase.Auth.FirebaseUser user;
    
    // Handle initialization of the necessary firebase modules:
    void InitializeFirebase() {
      Debug.Log("Setting up Firebase Auth");
      auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
      auth.StateChanged += AuthStateChanged;
      AuthStateChanged(this, null);
    }
    
    // Track state changes of the auth object.
    void AuthStateChanged(object sender, System.EventArgs eventArgs) {
      if (auth.CurrentUser != user) {
        bool signedIn = user != auth.CurrentUser && auth.CurrentUser != null;
        if (!signedIn && user != null) {
          Debug.Log("Signed out " + user.UserId);
        }
        user = auth.CurrentUser;
        if (signedIn) {
          Debug.Log("Signed in " + user.UserId);
        }
      }
    }
    
    void OnDestroy() {
      auth.StateChanged -= AuthStateChanged;
      auth = null;
    }
    

    我强烈建议您观看我的tutorial on Firebase Authentication,看看我是如何考虑将其与游戏集成的。 link you shared 是合适的,但我对我在您的代码中看到的各种 REST 调用有点好奇。

    如果您使用的是Firebase Unity SDKemail/password authentication 应该很简单:

    auth.CreateUserWithEmailAndPasswordAsync(email, password).ContinueWith(task => {
      if (task.IsCanceled) {
        Debug.LogError("CreateUserWithEmailAndPasswordAsync was canceled.");
        return;
      }
      if (task.IsFaulted) {
        Debug.LogError("CreateUserWithEmailAndPasswordAsync encountered an error: " + task.Exception);
        return;
      }
    
      // Firebase user has been created.
      Firebase.Auth.FirebaseUser newUser = task.Result;
      Debug.LogFormat("Firebase user created successfully: {0} ({1})",
          newUser.DisplayName, newUser.UserId);
    });
    

    创建用户和

    auth.SignInWithEmailAndPasswordAsync(email, password).ContinueWith(task => {
      if (task.IsCanceled) {
        Debug.LogError("SignInWithEmailAndPasswordAsync was canceled.");
        return;
      }
      if (task.IsFaulted) {
        Debug.LogError("SignInWithEmailAndPasswordAsync encountered an error: " + task.Exception);
        return;
      }
    
      Firebase.Auth.FirebaseUser newUser = task.Result;
      Debug.LogFormat("User signed in successfully: {0} ({1})",
          newUser.DisplayName, newUser.UserId);
    });
    

    让他们登录。也就是说,应该不需要使用RestClient

    2) 实时数据库

    一旦您通过身份验证,对 Firebase Realtime Database SDK 的任何调用都将自动使用 CurrentUser 值(正如我之前提到的 - 它在 SDK 的 C++ 端持续存在)。

    如果您希望使用rules to secure user data,例如:

    {
      "rules": {
        "users": {
          "$user_id": {
            // grants write access to the owner of this user account
            // whose uid must exactly match the key ($user_id)
            ".write": "$user_id === auth.uid"
          }
        }
      }
    }
    

    然后writing data:

    Database.DefaultInstance.GetReference($"/users/{FirebaseAuth.DefaultInstance.CurrentUser.UserId}/mySecret").SetValueAsync("flowers");
    

    应该可以工作。

    希望对大家有所帮助!

    --帕特里克

    【讨论】:

    • 你好 Patrick,很高兴在这里见到你,我看过你的 youtube 视频。看到使用 rest 调用进行注册/注册问题,我尝试完全使用 firebase sdk 编写以实现统一。我找到了一个很好的 sdk 教程。现在它的所有工作都像魅力一样。我只有一个问题,我不知道如何实现“发送电子邮件验证”,我看过他的文档。但我不确定是否在注册功能或登录功能中实现。如果你能帮助我,我很感激。我有这个用于注册codeshare.io/5zzv0N 的脚本和这个用于登录的脚本:codeshare.io/5OxALW
    • 新:我取得了一些进展,我现在可以发送电子邮件验证,但我需要编辑我的登录功能以防止在未验证电子邮件的情况下登录。可以帮我编辑我的 SignInHandler 吗?这是我的脚本: 注册:(我在 CreateUserWithEmailAsync() 函数中添加了电子邮件验证 codeshare.io/2KxQEo SignIn: codeshare.io/5zzbAb AuthManager: codeshare.io/anZwoM
    • 您究竟需要什么帮助?就用户验证而言,我认为您一目了然。游戏方面,您始终可以在启动时检查“IsEmailVerified”firebase.google.com/docs/reference/unity/class/firebase/auth/… 并重新路由到“请验证电子邮件屏幕”,而不是将用户移动到游戏。您可以使用规则来防止未经验证的用户与您的后端交互(firebase.google.com/docs/rules/rules-and-auth - 请参阅 email_verified)
    • 嗨,这是我的问题,我无法实现管理 IsEmailverified 值更改的方式,总是为假,如果我从应用程序注销并再次输入,我会得到 IsEmailVerified 为真,之后我可以加载我的场景,但我不想注册后注销。
    【解决方案2】:

    Firebase SDK 会自动保持身份验证状态,并尝试自动恢复它。您只需要编写代码来获取它,这涉及将侦听器附加到身份验证状态。

    请参阅 getting the currently signed in user 上的 Firebase 文档中的第一个 sn-p:

    获取当前用户的推荐方法是在 Auth 对象上设置监听器:

    Firebase.Auth.FirebaseAuth auth;
    Firebase.Auth.FirebaseUser user;
    
    // Handle initialization of the necessary firebase modules:
    void InitializeFirebase() {
      Debug.Log("Setting up Firebase Auth");
      auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
      auth.StateChanged += AuthStateChanged;
      AuthStateChanged(this, null);
    }
    
    // Track state changes of the auth object.
    void AuthStateChanged(object sender, System.EventArgs eventArgs) {
      if (auth.CurrentUser != user) {
        bool signedIn = user != auth.CurrentUser && auth.CurrentUser != null;
        if (!signedIn && user != null) {
          Debug.Log("Signed out " + user.UserId);
        }
        user = auth.CurrentUser;
        if (signedIn) {
          Debug.Log("Signed in " + user.UserId);
        }
      }
    }
    
    void OnDestroy() {
      auth.StateChanged -= AuthStateChanged;
      auth = null;
    }
    

    【讨论】:

    • 您好,感谢您的回复。我阅读了文档,但我不知道如何实现它,对不起。我试过这个脚本:codeshare.io/2KxBOP 我附加到我的第二个场景的一个空对象(第一个场景有登录脚本),但我不认为那是方式。你能解释一下这部分吗:你只需要编写代码来获取它,这涉及到将侦听器附加到身份验证状态。
    • 代码 sn-p 对我来说看起来不错。当GetUSER 被触发时,您的AuthStateChanged 方法应该被调用一次或两次。这没有发生吗? (顺便说一句,我不是 Unity 专家,所以希望我的条款正确)
    • 是的。 AuthStateChanged 被启动。我在那里查看了调试日志: void AuthStateChanged(object sender, System.EventArgs eventArgs) { Debug.Log("iniciando authstatechanged"); if (auth.CurrentUser != user) code continue.. ....但是“如果”语句没有运行。
    猜你喜欢
    • 2021-04-06
    • 2018-12-31
    • 1970-01-01
    • 2011-07-19
    • 2021-07-30
    • 2018-01-11
    • 2021-11-14
    • 1970-01-01
    相关资源
    最近更新 更多