服务器未从数据库中获取信息并将其传递给客户端。

19

我正在尝试使我的服务器从已登录的用户(web)中获取单点登录信息并将其传递给AS3客户端。

如果我在客户端中设置了特定的SSO(如下所示),则服务器会从数据库中提取用户。

目前,我收到了错误: ERROR 1: You have an invalid SSO ticket. Please re-login and then reload.

package 
{
    import com.archicruise.external.RoomManager;
    import com.archicruise.server.Connection;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.system.Security;
    import flash.system.System;

    public class Main extends Sprite 
    {
        [Embed(source = '../assets/client_back.png')] private static const clientBackImage:Class;

        public static var SITE_URL:String = "http://localhost/archicruise/";

        public var roomLoader:RoomManager;
        private var connection:Connection;

        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            //Add client background
            addChild(new clientBackImage() as Bitmap);

            //Got an SSO ticket?
            var ssoTicket:String = LoaderInfo(this.root.loaderInfo).parameters["sso"];
            if (ssoTicket == "" || ssoTicket == null) ssoTicket = "2e44550b0d6e98cc9f26c39e53213e24";

            //Initialize the connection
            Security.allowDomain("*");
            connection = new Connection("localhost", 9339, this, ssoTicket);;
        }

    }

}

当用户登录网站并启动带有SWF的页面后,我会获取ssoTicket值,方法如下:

var flashvars = {
    sso: "<?php echo $self['sso_ticket']; ?>"
};

服务器返回的处理程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ParticleFramework.Communication;
using ParticleFramework.Storage;
using ParticleFramework;
using MySql.Data.MySqlClient;
using ArchiCruise.Rooms;

namespace ArchiCruise.Users
{
    static class Handler
    {

        public static List<UserObject> clientObjects = new List<UserObject>();

        public static void login(string ssoTicket, TcpClient client)
        {
            if (ssoTicket == "")
            {
                client.Disconnect();
                return;
            }
            Log.Info("Client " + client.index + " logging in with SSO: " + ssoTicket);

            if (DBManager.database.getString("SELECT COUNT(*) FROM users` WHERE sso_ticket like '%" + ssoTicket.Trim() + "%'") != "0")
            {
                DBManager.database.closeClient();
                //build the user object
                UserObject userObject = newObject(ssoTicket, client);

                foreach (UserObject user in clientObjects)
                {
                    if (user.username == userObject.username)
                    {
                        user.tcpClient.Disconnect();
                    }
                }

                if (clientObjects.Count <= client.index || clientObjects[client.index] == null)
                {
                    client.userObject = userObject;
                    clientObjects.Add(userObject);
                }
                else
                {
                    client.userObject = userObject;
                    clientObjects[client.index] = userObject;
                }
                client.sendData("LO" + (char)13 + userObject.ToPrivate());
                DBManager.database.closeClient();
            }
            else
            {
                DBManager.database.closeClient();
                client.sendData("ER 1: You have an invalid SSO ticket. Please re-login and then reload.");
            }
        }

        public static void toAll(string Data)
        {
            foreach (UserObject user in clientObjects)
            {
                user.tcpClient.sendData(Data);
            }
        }

        public static void toAll(string Data, Boolean disconnect)
        {
            foreach (UserObject user in clientObjects)
            {
                user.tcpClient.sendData(Data);
                if (disconnect) user.tcpClient.Disconnect();
            }
        }

        public static void toUser(string Data, string uname)
        {
            foreach (UserObject user in clientObjects)
            {
                if (user.username.ToLower() == uname.ToLower())
                {
                    user.tcpClient.sendData(Data);
                }
            }
        }

        public static void toUser(string Data, string uname, Boolean disconnect)
        {
            foreach (UserObject user in clientObjects)
            {
                if (user.username.ToLower() == uname.ToLower())
                {
                    user.tcpClient.sendData(Data);
                    if (disconnect)
                    {
                        user.tcpClient.Disconnect();
                    }
                }
            }
        }

        public static void toRoom(int roomID, TcpClient client)
        {
            if (clientObjects.Count >= client.index && client.userObject.roomID != roomID)
            {
                Log.Info("Client " + client.index + " going to public room " + roomID);

                if (DBManager.database.getString("SELECT COUNT(*) FROM `public` WHERE `id` = '" + roomID + "';") != "0")
                {
                    DBManager.database.closeClient();

                    //kick plz
                    if (client.userObject.roomID > 0)
                    {
                        client.userObject.toRoom("KO " + client.userObject.username);
                    }

                    //update user object
                    MySqlDataReader mysqlRead = DBManager.database.getCommand("SELECT * FROM `public` WHERE `id` = '" + roomID + "' LIMIT 1").ExecuteReader();
                    mysqlRead.Read();

                    client.userObject.toRoom(roomID, Convert.ToInt32(mysqlRead["startpos"].ToString().Split(',')[0]), Convert.ToInt32(mysqlRead["startpos"].ToString().Split(',')[1]));

                    client.sendData("RO" + mysqlRead["layout"].ToString() + (char)13 + mysqlRead["name"].ToString() + (char)13 + (char)12 + mysqlRead["heightmap"].ToString() + (char)12 + mysqlRead["warps"].ToString());

                    DBManager.database.closeClient();
                }
                else
                {
                    DBManager.database.closeClient();
                    client.sendData("ER 1: You have an invalid SSO ticket. Please re-login and then reload.");
                }
            }
        }

        public static void moveUser(TcpClient client, int _x, int _y)
        {
            client.userObject.x = _x;
            client.userObject.y = _y;
            client.userObject.toRoom("MV " + client.userObject.username + " " + _x + " " + _y);
        }

        public static void sendNavigationList(TcpClient client, int pub)
        {
            string nList = "NV" + (char)13;
            MySqlDataReader mysqlRead = DBManager.database.getCommand("SELECT * FROM `public` WHERE `show` = 'yes' AND `public` = '" + pub + "'").ExecuteReader();

            while (mysqlRead.Read())
            {
                nList += mysqlRead["id"].ToString() + (char)14 + mysqlRead["name"].ToString() + (char)13;
            }

            DBManager.database.closeClient();

            client.sendData(nList);
        }

        public static void sendUserList(TcpClient client)
        {
            string userList = "UE" + (char)13;

            client.userObject.toRoom("UL" + (char)13 + client.userObject.ToString());

            foreach (UserObject user in clientObjects)
            {
                if (user.roomID == client.userObject.roomID && user.tcpClient != null)
                {
                    if (user.username != client.userObject.username && !userList.Contains(user.username + "@"))
                    {
                        userList += user.ToString();
                    }
                }
            }

            client.sendData(userList);

            //Send room object
            client.sendData("RB" + (char)13 + RoomObjects.buildObjects(client.userObject.roomID));
        }

        public static UserObject newObject(string ssoTicket, TcpClient tClient)
        {
            MySqlDataReader mysqlRead = DBManager.database.getCommand("SELECT * FROM `users` WHERE `sso_ticket` = '" + ssoTicket + "' LIMIT 1").ExecuteReader();
            mysqlRead.Read();

            return new UserObject(mysqlRead["name"].ToString(), Convert.ToInt32(mysqlRead["rank"]), Convert.ToInt32(mysqlRead["credits"]), tClient);
        }

    }
}

请求的DBManager类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ParticleFramework.Storage
{
    static class DBManager
    {
        public static Database database;

        public static Boolean Initialize(string type, string user, string pass, string host, string dbname)
        {
            switch (type)
            {
                case "sql":
                    database = new MySQL();
                    break;

                default:
                    Log.Error("Invalid database type! (" + type + ")");
                    break;
            }

            if (database != null)
            {
                return database.connect(user, pass, dbname, host);
            }
            else
            {
                return false;
            }
        }
    }
}

MySQL 类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;

namespace ParticleFramework.Storage
{
    class MySQL : Database
    {
        private MySqlConnection connection;

        public Boolean connect(string username, string password, string database, string host)
        {
            try
            {
                connection = new MySqlConnection(buildConnectionString(username, password, database, host));
                Console.WriteLine("Database connected.  Running test query...");
                getString("SHOW TABLES FROM `" + database + "`");
                Log.Info("Test query succeeded.  Database initialized.");
                closeClient();

                return true;
            }
            catch (Exception e)
            {
                Log.Error("MySQL Connect: " + e.Message);
                return false;
            }
        }

        public string getString(string query)
        {
            try
            {
                string resultStr = getCommand(query).ExecuteScalar().ToString();
                closeClient();

                return resultStr;
            }
            catch (Exception e)
            {
                Log.Error("MySQL getString: " + e.Message);
                return "";
            }
        }

        public MySqlCommand getCommand(string query)
        {
            try
            {
                if (connection.State != System.Data.ConnectionState.Closed)
                {
                    connection.Close();
                }

                MySqlCommand command = newCommand();
                command.CommandText = query;
                connection.Open();
                return command;
            }
            catch (Exception e)
            {
                Log.Error("MySQL getCommand: " + e.Message);
                return null;
            }
        }

        public void noCommand(string query)
        {
            try
            {
                if (connection.State != System.Data.ConnectionState.Closed)
                {
                    connection.Close();
                }

                MySqlCommand command = newCommand();
                command.CommandText = query;
                connection.Open();
                command.ExecuteNonQuery();
                connection.Close();
            }
            catch (Exception e)
            {
                Log.Error("MySQL noCommand: " + e.Message);
            }
        }

        public void closeClient()
        {
            try
            {
                if (connection.State == System.Data.ConnectionState.Open)
                {
                    connection.Close();
                }
            }
            catch (Exception e)
            {
                Log.Error("MySQL closeClient: " + e.Message);
            }
        }

        public MySqlCommand newCommand()
        {
            try
            {
                return connection.CreateCommand();
            }
            catch (Exception e)
            {
                Log.Error("MySQL newCommand: " + e.Message);
                return null;
            }
        }

        public string buildConnectionString(string username, string password, string database, string host)
        {
            return "Database=" + database + ";Data Source=" + host + ";User Id=" + username + ";Password=" + password;
        }
    }
}

数据库类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;

namespace ParticleFramework.Storage
{
    interface Database
    {
        Boolean connect(string username, string password, string database, string host);
        MySqlCommand newCommand();
        MySqlCommand getCommand(string query);

        string buildConnectionString(string username, string password, string database, string host);
        string getString(string query);
        void noCommand(string query);

        void closeClient();
    }
}

单点登录字符串变更后的日志信息

>[1/1/0001 00:00:00] 127.0.0.1connected.  Full 127.0.0.1:56765
>[1/1/0001 00:00:00] Got LO null  from client 0
>[1/1/0001 00:00:00] Client 0 logging in with SSO: null
>[ERROR]Packet handler: MySql.Data.MySqlClient.MySqlException (0x80004005): Invalid attempt to access a field before calling Read()
>   at MySql.Data.MySqlClient.ResultSet.get_Item(Int32 index)
>   at MySql.Data.MySqlClient.MySqlDataReader.GetFieldValue(Int32 index, Boolean checkNull)
>   at MySql.Data.MySqlClient.MySqlDataReader.GetValue(Int32 i)
>   at MySql.Data.MySqlClient.MySqlDataReader.get_Item(Int32 i)
>   at MySql.Data.MySqlClient.MySqlDataReader.get_Item(String name)
>   at ArchiCruise.Users.Handler.newObject(String ssoTicket, TcpClient tClient) in C:\Users\Daniel\Desktop\AC\Particle Server\Particle Server\ArchiCruise\Users\Handler.cs:line 188
>   at ArchiCruise.Users.Handler.login(String ssoTicket, TcpClient client) in C:\Users\Daniel\Desktop\AC\Particle Server\Particle Server\ArchiCruise\Users\Handler.cs:line 31
>   at ArchiCruise.ArchiCruisePackets.handle(String packet, TcpClient client) in C:\Users\Daniel\Desktop\AC\Particle Server\Particle Server\ArchiCruise\ArchiCruisePackets.cs:line 23
>[1/1/0001 00:00:00] Client0 disconnected and removed.

Tcpclient 类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ParticleFramework.Communication
{
    class TcpClient
    {
        #region Required Variables
        public Socket socket;
        public int index;
        private byte[] dataBuffer = new byte[0x400];
        private AsyncCallback ReceiveCallback;
        private AsyncCallback SendCallback;
        #endregion

        #region ArchiCruise Vars
        public ArchiCruise.Users.UserObject userObject;
        public string ip;
        #endregion

        public TcpClient(Socket sock, int num)
        {
            index = num;
            socket = sock;

            ip = socket.RemoteEndPoint.ToString().Split(new char[] { ':' })[0];

            ReceiveCallback = new AsyncCallback(this.ReceivedData);
            SendCallback = new AsyncCallback(this.sentData);

            this.WaitForData();
        }

        public void Disconnect()
        {
            if (socket.Connected)
            {
                socket.Close();
                if (userObject != null) userObject.remove();
                Particle.Server.removeClient(this);
                Log.Info("Client" + this.index + " disconnected and removed.");
                Console.WriteLine("Client" + this.index + " disconnected.");
            }
        }

        private void ReceivedData(IAsyncResult iAr)
        {
            try
            {
                int count = 0;

                try
                {
                    count = socket.EndReceive(iAr);
                }
                catch
                {
                    Disconnect();
                }

                StringBuilder builder = new StringBuilder();
                builder.Append(System.Text.Encoding.Default.GetString(this.dataBuffer, 0, count));
                string str = System.Text.Encoding.Default.GetString(this.dataBuffer, 0, count);

                if (str.Contains("<policy-file-requet/>"))
                {
                    Log.Info("Sending policy file to client" + this.index);
                    rawSend("<?xml version\"1.0\"?><cross-domain-policy><allow-access-from-domain=\"*\" to-ports=\"*\" /><cross-domain-policy>" + Convert.ToChar(0));
                }
                else if (!(str.ToString() == ""))
                {
                    string packet = str.Substring(0, str.Length - 1);
                    //packet = ArchiCruise.Security.Encryption.decrypt(packet);
                    Log.Info("Got " + str + " from client " + this.index);

                    Particle.packetClass.handle(packet, this);
                }
                else
                {
                    Disconnect();
                }
            }
            catch (Exception exception)
            {
                Log.Info("Data recieve error: " + exception.ToString() + " " + exception.Source);
                Disconnect();
            }
            finally
            {
                this.WaitForData();
            }
        }

        private void WaitForData()
        {
            try
            {
                socket.BeginReceive(this.dataBuffer, 0, this.dataBuffer.Length, SocketFlags.None, this.ReceiveCallback, socket);
            }
            catch
            {
                Disconnect();
            }
        }

        public void sendData(string Data)
        {
            Data += (char)1;
            rawSend(Data);
        }

        internal void rawSend(string Data)
        {
            try
            {
                Data += "\0";
                byte[] bytes = System.Text.Encoding.Default.GetBytes(Data);

                socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(this.sentData), null);
                Log.Info("Sent " + Data + " to client " + this.index);
            }
            catch
            {
                Disconnect();
            }
        }

        private void sentData(IAsyncResult iAr)
        {
            try
            {
                socket.EndSend(iAr);
            }
            catch
            {
                Disconnect();
            }
        }
    }
}

请问您能否展示一下如何在DOM中的SWF对象上注入flashvars变量(我想是通过JavaScript实现的)?因为您需要将其与某个地方关联起来... - anolsi
我已经完成了flashvars,但是我在工作中没有最新的代码。我知道它正在注入,因为它被正确记录,但是在上面的处理程序类中,在 Log.Info("Client " + client.index + " logging in with SSO: " + ssoTicket); 之后它会断开客户端连接。 - Sauced Apples
我认为您的PHP正确生成和发送了ssoTicket,但它没有被正确加载到swf中。这使得swf向C#发送了不正确的票据。这就是为什么我想看看您如何将sssoTicket传递给swf对象。 - anolsi
我马上会添加,但当我启动服务器并加载SWF文件后,如果记录正确的SSO,则为日志。 - Sauced Apples
@anolsi,看起来跨域策略是导致问题的原因。它在发送策略后刷新连接(显然是有意为之),这会更新ssoticket。现在我只需要找到一种方法,在发送策略时停止sso的更新即可。 - Sauced Apples
显示剩余10条评论
2个回答

1
我建议您使用MySQL ORM。您的代码非常容易出错,并且极易受到SQL注入攻击。
但是,从您的错误日志中可以看出,您没有检查SQL查询是否已正确执行并具有值。您可以使用以下if检查轻松完成此操作:
public static UserObject newObject(string ssoTicket, TcpClient tClient)
{
    string sqlQuery = "SELECT * FROM `users` WHERE `sso_ticket` = '" + ssoTicket + "' LIMIT 1";
    MySqlDataReader mysqlRead = DBManager.database.getCommand( sqlQuery ).ExecuteReader();
    if (mysqlRead.Read()) // read the query and check if we got any data
    {
        return new UserObject(mysqlRead["name"].ToString(), Convert.ToInt32(mysqlRead["rank"]), Convert.ToInt32(mysqlRead["credits"]), tClient);  
    }
    else
    {
       Log.Error("sqlQuery failed : " + sqlQuery );
       return null; //you should check the returned value if its null or not to prevent further problems.
    }                           
}

使用这段代码,您可以检查查询是否有误。我建议您逐步调试并查看变量中是否有正确的值。请参阅微软的Visual Studio调试了解更多有关调试的信息。

0

如果您能够定制此答案以显示您将如何更改问题,那么我将找出代码并检查,因为这已经快一年了(仍未解决)。 - Sauced Apples

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接