private async static ETTask RealmToGate(Session session, User user, R2C_Authentication response, bool isRefreshToken)
        {
            // 隨機分配GateServer
            StartConfig config = Game.Scene.GetComponent <RealmGateAddressComponent>().GetAddress();

            // Log.Debug($"gate address: {MongoHelper.ToJson(config)}");
            IPEndPoint innerAddress = config.GetComponent <InnerConfig>().IPEndPoint;
            Session    gateSession  = Game.Scene.GetComponent <NetInnerComponent>().Get(innerAddress);
            //Game.Scene.GetComponent<PingComponent>().RemoveSession(session.Id);

            // 向Gate請求一個Key,Client可以拿這個Key連接Gate
            G2R_GetLoginKey g2RGetLoginKey = (G2R_GetLoginKey)await gateSession.Call(new R2G_GetLoginKey()
            {
                Uid = user.Id
            });

            string outerAddress = config.GetComponent <OuterConfig>().Address2;

            // 創造權杖
            if (isRefreshToken)
            {
                SignInCryptographyHelper.Token tok = new SignInCryptographyHelper.Token
                {
                    uid = user.Id,
                    lastCreateTokenAt = user.lastCreateTokenAt,
                    salt = user.salt,
                };

                string token = SignInCryptographyHelper.EncodeToken(tok);
                response.Token = token;
            }

            PlayerRideTotalInfo playerRideTotalInfo = await UserDataHelper.QueryUserRideAllRecord(user);

            response.Error   = ErrorCode.ERR_Success;
            response.Address = outerAddress;
            response.Key     = g2RGetLoginKey.Key;
            response.Data    = new PlayerBaseInfo
            {
                Uid      = user.Id,
                Name     = user.name,
                Sex      = user.gender,
                Location = user.location,
                Height   = user.height,
                Weight   = user.weight,
                Birthday = user.birthday,
                CreateAt = user.createAt,
                // 校時用
                LastOnlineAt = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                CharSetting  = user.playerCharSetting,
                TotalInfo    = playerRideTotalInfo,
                Language     = user.language,
            };
            response.LinkTypes.Clear();
            response.LinkTypes.AddRange(await GetAllLinkType(user.Id));
        }
        public async static ETTask AuthenticationByToken(Session session, AuthenticationInfo info, R2C_Authentication response)
        {
            SignInCryptographyHelper.Token tok = null;
            try
            {
                tok = SignInCryptographyHelper.DecodeToken(info.Secret);
                if (tok == null)
                {
                    response.Error = ErrorCode.ERR_InvalidToken;
                    return;
                }
            }
            catch (Exception e)
            {
                response.Error = ErrorCode.ERR_InvalidToken;
                return;
            }

            User user = await UserDataHelper.FindOneUser(tok.uid);

            if (user != null)
            {
                if (user.salt != tok.salt || user.lastCreateTokenAt != tok.lastCreateTokenAt)
                {
                    response.Error = ErrorCode.ERR_InvalidToken;
                }
                else
                {
                    await SignInByUid(session, user, response, info.FirebaseDeviceToken, false, UserDataHelper.tagToken);
                }
            }
            else
            {
                response.Error = ErrorCode.ERR_AccountDoesntExist;
            }
        }