首页 > 代码库 > Asp.net mvc与PHP的Session共享的实现

Asp.net mvc与PHP的Session共享的实现

最近在做的一个ASP.NET MVC的项目,要用到第三方的php系统,为了实现两个系统的互联互通。决定将两者的session打通共享。让asp.net mvc 和php 都能正常访问和修改Session内容。

 

在决定实现之前,先搜索了一下院子里有没有相类似的文章,对于跨语言的程序互通,有两种方案:

(1)       SSO单点登录,其实就是把用户名和密码传给另一个系统在另一个系统上自动创建session 来解决。

(2)       还有就是用同一套Session,在数据库或缓存上架设session服务。

第一种方案因为两套系统的交互比较多,不仅仅是登陆和验证,所以不适合。

第二种方案网上资料不多,不过关于session 数据库持久化的内容不少。选择第二种方案。

 

先说一下 大概的思路:

(1)       将Asp.net 的Session 采用mysql 存储。

(2)       将PHP的session也采用同一个数据库,同一张表存储。

(3)       修改Asp.net的Session内容的序列化和反序列化方式,使之与PHP的序列号方式相同。

(4)       修改两者的 cookie 中的sessionID 名称让二者采用同一个Sessionid名称。

(5)       修改两者的cookie作用域,使两者的Cookie Domin 位于主域名如 xxx.com。

(6)       解决后续出现的问题。

 

* php session 序列化格式:   user_id|s:1:"3";user_name|s:4:"test";email|s:12:"fdff@fdf.com";avatarSrc|s:0:"";

 

闲话不多说直接上代码。

--Mysql 数据表的创建代码CREATE TABLE `sessions` (  `SessionId` VARCHAR(80) NOT NULL,  `ApplicationName` VARCHAR(255) NOT NULL,  `Created` DATETIME NOT NULL,  `Expires` DATETIME NOT NULL,  `LockDate` DATETIME NOT NULL,  `LockId` INT(10) UNSIGNED NOT NULL,  `Timeout` INT(10) UNSIGNED NOT NULL,  `Locked` SMALLINT(1) UNSIGNED NOT NULL,  `SessionItems` LONGTEXT NOT NULL,  `Flags` INT(10) UNSIGNED NOT NULL,  PRIMARY KEY (`SessionId`,`ApplicationName`)) ENGINE=INNODB DEFAULT CHARSET=utf8

  

Asp.net  SessionProvider 代码

public class SessionProvider : SessionStateStoreProviderBase    {        private SessionStateSection pConfig = null;        private string connectionString;        private ConnectionStringSettings pConnectionStringSettings;        private string eventSource = "OdbcSessionStateStore";        private string eventLog = "Application";        private string exceptionMessage =          "An exception occurred. Please contact your administrator.";        private string pApplicationName;        //        // If false, exceptions are thrown to the caller. If true,        // exceptions are written to the event log.        //        private bool pWriteExceptionsToEventLog = false;        public bool WriteExceptionsToEventLog        {            get { return pWriteExceptionsToEventLog; }            set { pWriteExceptionsToEventLog = value; }        }        //        // The ApplicationName property is used to differentiate sessions        // in the data source by application.        //        public string ApplicationName        {            get { return pApplicationName; }        }        public override void Initialize(string name, NameValueCollection config)        {            //            // Initialize values from web.config.            //            if (config == null)                throw new ArgumentNullException("config");            if (name == null || name.Length == 0)                name = "OdbcSessionStateStore";            if (String.IsNullOrEmpty(config["description"]))            {                config.Remove("description");                config.Add("description", "Sample ODBC Session State Store provider");            }            // Initialize the abstract base class.            base.Initialize(name, config);            //            // Initialize the ApplicationName property.            //            pApplicationName =              System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;            //            // Get <sessionState> configuration element.            //            Configuration cfg =              WebConfigurationManager.OpenWebConfiguration(ApplicationName);            pConfig =              (SessionStateSection)cfg.GetSection("system.web/sessionState");            //            // Initialize connection string.            //            pConnectionStringSettings =              ConfigurationManager.ConnectionStrings["MySqlSessionServices"];            //if (pConnectionStringSettings == null ||            //  pConnectionStringSettings.ConnectionString.Trim() == "")            //{            //    throw new ProviderException("Connection string cannot be blank.");            //}            connectionString = pConnectionStringSettings.ConnectionString;            //            // Initialize WriteExceptionsToEventLog            //            pWriteExceptionsToEventLog = false;            //if (config["writeExceptionsToEventLog"] != null)            //{            //    if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE")            //        pWriteExceptionsToEventLog = true;            //}        }        //        // SessionStateStoreProviderBase members        //        public override void Dispose()        {        }        //        // SessionStateProviderBase.SetItemExpireCallback        //        public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)        {            return false;        }        //        // SessionStateProviderBase.SetAndReleaseItemExclusive        //        public override void SetAndReleaseItemExclusive(HttpContext context,          string id,          SessionStateStoreData item,          object lockId,          bool newItem)        {            // Serialize the SessionStateItemCollection as a string.            string sessItems = Serialize((SessionStateItemCollection)item.Items);            #region odbc代码            //MySqlConnection conn = new MySqlConnection(connectionString);            //MySqlCommand cmd;            //MySqlCommand deleteCmd = null;            #endregion            MySqlConnection conn = new MySqlConnection(connectionString);            MySqlCommand cmd;            MySqlCommand deleteCmd = null;            if (newItem)            {                // MySqlCommand to clear an existing expired session if it exists.                deleteCmd = new MySqlCommand("DELETE FROM Sessions " +                    "WHERE SessionId = ? AND ApplicationName = ? AND Expires < ?", conn);                deleteCmd.Parameters.Add("@SessionId",MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar, 255).Value = http://www.mamicode.com/ApplicationName;"@Expires", MySqlDbType.DateTime).Value = http://www.mamicode.com/DateTime.Now;"INSERT INTO Sessions " +                  " (SessionId, ApplicationName, Created, Expires, " +                  "  LockDate, LockId, Timeout, Locked, SessionItems, Flags) " +                  " Values(?, ?, ?, ?, ?, ? , ?, ?, ?, ?)", conn);                cmd.Parameters.Add("@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar, 255).Value = http://www.mamicode.com/ApplicationName;"@Created", MySqlDbType.DateTime).Value = http://www.mamicode.com/DateTime.Now;"@Expires", MySqlDbType.DateTime).Value = http://www.mamicode.com/DateTime.Now.AddMinutes((Double)item.Timeout);"@LockDate", MySqlDbType.DateTime).Value = http://www.mamicode.com/DateTime.Now;"@LockId", MySqlDbType.Int32).Value = http://www.mamicode.com/0;"@Timeout", MySqlDbType.Int32).Value = http://www.mamicode.com/item.Timeout;"@Locked", MySqlDbType.Bit).Value = http://www.mamicode.com/false;"@SessionItems", MySqlDbType.VarChar, sessItems.Length).Value = http://www.mamicode.com/sessItems;"@Flags", MySqlDbType.Int32).Value = http://www.mamicode.com/0;"UPDATE Sessions SET Expires = ?, SessionItems = ?, Locked = ? " +                  " WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn);                cmd.Parameters.Add("@Expires", MySqlDbType.DateTime).Value =http://www.mamicode.com/DateTime.Now.AddMinutes((Double)item.Timeout);"@SessionItems", MySqlDbType.VarChar, sessItems.Length).Value = http://www.mamicode.com/sessItems;"@Locked", MySqlDbType.Bit).Value = http://www.mamicode.com/false;"@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar, 255).Value = http://www.mamicode.com/ApplicationName;"@LockId", MySqlDbType.Int32 ).Value = http://www.mamicode.com/lockId;"SetAndReleaseItemExclusive");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                conn.Close();            }        }        //        // SessionStateProviderBase.GetItem        //        public override SessionStateStoreData GetItem(HttpContext context,          string id,          out bool locked,          out TimeSpan lockAge,          out object lockId,          out SessionStateActions actionFlags)        {            return GetSessionStoreItem(false, context, id, out locked,              out lockAge, out lockId, out actionFlags);        }        //        // SessionStateProviderBase.GetItemExclusive        //        public override SessionStateStoreData GetItemExclusive(HttpContext context,          string id,          out bool locked,          out TimeSpan lockAge,          out object lockId,          out SessionStateActions actionFlags)        {            return GetSessionStoreItem(true, context, id, out locked,              out lockAge, out lockId, out actionFlags);        }        //        // GetSessionStoreItem is called by both the GetItem and         // GetItemExclusive methods. GetSessionStoreItem retrieves the         // session data from the data source. If the lockRecord parameter        // is true (in the case of GetItemExclusive), then GetSessionStoreItem        // locks the record and sets a new LockId and LockDate.        //        private SessionStateStoreData GetSessionStoreItem(bool lockRecord,          HttpContext context,          string id,          out bool locked,          out TimeSpan lockAge,          out object lockId,          out SessionStateActions actionFlags)        {            // Initial values for return value and out parameters.            SessionStateStoreData item = null;            lockAge = TimeSpan.Zero;            lockId = null;            locked = false;            actionFlags = 0;            // ODBC database connection.            MySqlConnection conn = new MySqlConnection(connectionString);            // MySqlCommand for database commands.            MySqlCommand cmd = null;            // DataReader to read database record.            MySqlDataReader reader = null;            // DateTime to check if current session item is expired.            DateTime expires;            // String to hold serialized SessionStateItemCollection.            string serializedItems = "";            // True if a record is found in the database.            bool foundRecord = false;            // True if the returned session item is expired and needs to be deleted.            bool deleteData = http://www.mamicode.com/false;"UPDATE Sessions SET" +                      " Locked = ?, LockDate = ? " +                      " WHERE SessionId = ? AND ApplicationName = ? AND Locked = ? AND Expires > ?", conn);                    cmd.Parameters.Add("@Locked", MySqlDbType.Bit).Value = http://www.mamicode.com/true;"@LockDate", MySqlDbType.DateTime).Value= http://www.mamicode.com/DateTime.Now;"@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar, 255).Value = http://www.mamicode.com/ApplicationName;"@Lockid", MySqlDbType.Int32).Value = http://www.mamicode.com/0;"@Expires", MySqlDbType.DateTime).Value = http://www.mamicode.com/DateTime.Now;"SELECT Expires, SessionItems, LockId, LockDate, Flags, Timeout " +                  "  FROM Sessions " +                  "  WHERE SessionId = ? AND ApplicationName = ?", conn);                cmd.Parameters.Add("@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,                  255).Value = http://www.mamicode.com/ApplicationName;"DELETE FROM Sessions " +                      "WHERE SessionId = ? AND ApplicationName = ?", conn);                    cmd.Parameters.Add("@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,                      255).Value = http://www.mamicode.com/ApplicationName;"UPDATE Sessions SET" +                      " LockId = ?, Flags = 0 " +                      " WHERE SessionId = ? AND ApplicationName = ?", conn);                    cmd.Parameters.Add("@LockId", MySqlDbType.Int32).Value = http://www.mamicode.com/lockId;"@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar, 255).Value = http://www.mamicode.com/ApplicationName;"GetSessionStoreItem");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                if (reader != null) { reader.Close(); }                conn.Close();            }            return item;        }        //        // Serialize is called by the SetAndReleaseItemExclusive method to         // convert the SessionStateItemCollection into a Base64 string to            // be stored in an Access Memo field.        //        private string Serialize(SessionStateItemCollection items)        {                       items["LastName"] = "Wilson";            items["FirstName"] = "Dan";            string ret = "";            for (int i = 0; i < items.Count;i++ )            {                string str = "";                if (items[i] != null)                {                    str = items.Keys[i] + "|s:" + items[i].ToString().Length + ":\"" + items[i].ToString() + "\";";                }                else                {                    str = items.Keys[i] + "|N;";                }                ret += str;            }            return ret;        }        #region base64 序列化session        //        // DeSerialize is called by the GetSessionStoreItem method to         // convert the Base64 string stored in the Access Memo field to a         // SessionStateItemCollection.        //        //private SessionStateStoreData Deserialize(HttpContext context,        //  string serializedItems, int timeout)        //{        //    MemoryStream ms =        //      new MemoryStream(Convert.FromBase64String(serializedItems));        //    SessionStateItemCollection sessionItems =        //      new SessionStateItemCollection();        //    if (ms.Length > 0)        //    {        //        BinaryReader reader = new BinaryReader(ms);        //        sessionItems = SessionStateItemCollection.Deserialize(reader);        //    }        //    return new SessionStateStoreData(sessionItems,        //      SessionStateUtility.GetSessionStaticObjects(context),        //      timeout);        //}        #endregion       /// <summary>       /// 自定义获取session项       /// </summary>       /// <param name="context"></param>       /// <param name="serializedItems"></param>       /// <param name="timeout"></param>       /// <returns></returns>        private SessionStateStoreData Deserialize(HttpContext context,         string serializedItems, int timeout)        {                       SessionStateItemCollection sessionItems = new SessionStateItemCollection();                  string[] arry = serializedItems.Split(‘;‘);            foreach (string item in arry)            {                if (!string.IsNullOrEmpty(item))                {                    string strKey = item.Split(‘|‘)[0];                    string other = item.Split(‘|‘)[1];                    string strValuehttp://www.mamicode.com/= "";                    if (other == "N")                    {                        sessionItems[strKey]=null;                    }                    else if (other.Split(‘:‘).Count() > 2)                    {//s:1:"1"                        strValue = http://www.mamicode.com/other.Split(‘:‘)[2];"\"", "");                    }                    else                    {                        sessionItems[strKey] = null;                    }                }            }            return new SessionStateStoreData(sessionItems,              SessionStateUtility.GetSessionStaticObjects(context),              timeout);        }        public override void ReleaseItemExclusive(HttpContext context,          string id,          object lockId)        {            MySqlConnection conn = new MySqlConnection(connectionString);            MySqlCommand cmd =              new MySqlCommand("UPDATE Sessions SET Locked = 0, Expires = ? " +              "WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn);            cmd.Parameters.Add("@Expires", MySqlDbType.DateTime).Value =              http://www.mamicode.com/DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);"@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,              255).Value = http://www.mamicode.com/ApplicationName;"@LockId", MySqlDbType.Int32).Value = http://www.mamicode.com/lockId;"ReleaseItemExclusive");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                conn.Close();            }        }        //        // SessionStateProviderBase.RemoveItem        //        public override void RemoveItem(HttpContext context,          string id,          object lockId,          SessionStateStoreData item)        {            MySqlConnection conn = new MySqlConnection(connectionString);            MySqlCommand cmd = new MySqlCommand("DELETE * FROM Sessions " +              "WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn);            cmd.Parameters.Add("@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,              255).Value = http://www.mamicode.com/ApplicationName;"@LockId", MySqlDbType.Int32).Value = http://www.mamicode.com/lockId;"RemoveItem");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                conn.Close();            }        }        //        // SessionStateProviderBase.CreateUninitializedItem        //        public override void CreateUninitializedItem(HttpContext context,          string id,          int timeout)        {            //MySqlConnection conn = new MySqlConnection(connectionString);            MySqlConnection conn = new MySqlConnection(connectionString);            MySqlCommand cmd = new MySqlCommand("INSERT INTO Sessions " +              " (SessionId, ApplicationName, Created, Expires, " +              "  LockDate, LockId, Timeout, Locked, SessionItems, Flags) " +              " Values(?, ?, ?, ?, ?, ? , ?, ?, ?, ?)", conn);            cmd.Parameters.Add("@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,              255).Value = http://www.mamicode.com/ApplicationName;"@Created", MySqlDbType.DateTime).Value              = http://www.mamicode.com/DateTime.Now;"@Expires", MySqlDbType.DateTime).Value              = http://www.mamicode.com/DateTime.Now.AddMinutes((Double)timeout);"@LockDate", MySqlDbType.DateTime).Value              = http://www.mamicode.com/DateTime.Now;"@LockId", MySqlDbType.Int32).Value = http://www.mamicode.com/0;"@Timeout", MySqlDbType.Int32).Value = http://www.mamicode.com/timeout;"@Locked", MySqlDbType.Bit).Value = http://www.mamicode.com/false;"@SessionItems", MySqlDbType.VarChar, 0).Valuehttp://www.mamicode.com/= "";            cmd.Parameters.Add("@Flags", MySqlDbType.Int32).Value = http://www.mamicode.com/1;"CreateUninitializedItem");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                conn.Close();            }        }        //        // SessionStateProviderBase.CreateNewStoreData        //        public override SessionStateStoreData CreateNewStoreData(          HttpContext context,          int timeout)        {            return new SessionStateStoreData(new SessionStateItemCollection(),              SessionStateUtility.GetSessionStaticObjects(context),              timeout);        }        //        // SessionStateProviderBase.ResetItemTimeout        //        public override void ResetItemTimeout(HttpContext context,                                              string id)        {            MySqlConnection conn = new MySqlConnection(connectionString);            MySqlCommand cmd =              new MySqlCommand("UPDATE Sessions SET Expires = ? " +              "WHERE SessionId = ? AND ApplicationName = ?", conn);            cmd.Parameters.Add("@Expires", MySqlDbType.DateTime).Value              = http://www.mamicode.com/DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);"@SessionId", MySqlDbType.VarChar, 80).Value = http://www.mamicode.com/id;"@ApplicationName", MySqlDbType.VarChar,              255).Value = http://www.mamicode.com/ApplicationName;"ResetItemTimeout");                    throw new ProviderException(exceptionMessage);                }                else                    throw e;            }            finally            {                conn.Close();            }        }             public override void InitializeRequest(HttpContext context)        {        }        public override void EndRequest(HttpContext context)        {        }        private void WriteToEventLog(Exception e, string action)        {            EventLog log = new EventLog();            log.Source = eventSource;            log.Log = eventLog;            string message =              "An exception occurred communicating with the data source.\n\n";            message += "Action: " + action + "\n\n";            message += "Exception: " + e.ToString();            log.WriteEntry(message);        }}

  Php  Session 提供程序代码

 

function sess_open($save_path, $session_name) {     global $SESS_DBHOST, $SESS_DBNAME, $SESS_DBUSER, $SESS_DBPASS, $SESS_DBH;     if (! $SESS_DBH = mysql_pconnect($SESS_DBHOST, $SESS_DBUSER, $SESS_DBPASS)) {         echo "<li>Can‘t connect to $SESS_DBHOST as $SESS_DBUSER";         echo "<li>MySQL Error: " . mysql_error();         die;     }     if (! mysql_select_db($SESS_DBNAME, $SESS_DBH)) {         echo "<li>Unable to select database $SESS_DBNAME";         die;     }     return true; } function sess_close() {     return true; } function sess_read($key) {     global $SESS_DBH, $SESS_LIFE;     $qry = "SELECT SessionItems FROM sessions WHERE SessionId = ‘$key‘ and ApplicationName=‘/‘   AND Expires > ‘" .date("Y-m-d H:i:s")."‘";     $qid = mysql_query($qry, $SESS_DBH);     if (list($value) = mysql_fetch_row($qid)) {         return $value;     }     //else    //{    //    sess_write($key,‘‘);    //    return ‘‘;    //}    return false; } function sess_write($key, $val) {     global $SESS_DBH, $SESS_LIFE;         $Tnow=date("Y-m-d H:i:s");//当前时间    $expiry =date("Y-m-d H:i:s", time() + $SESS_LIFE); //过期时间     $value = http://www.mamicode.com/addslashes($val); "INSERT INTO sessions (SessionId, ApplicationName, Created, Expires, ".            "  LockDate, LockId, Timeout, Locked, SessionItems, Flags) ".            "  VALUES (‘$key‘,‘/‘, ‘$Tnow‘ ,‘$expiry‘,‘$Tnow‘, 0, 20,0, ‘$value‘,0 )";     $qid = mysql_query($qry, $SESS_DBH);     if (! $qid) {         $qry = "UPDATE sessions SET Expires = ‘$expiry‘, SessionItems = ‘$value‘ WHERE SessionId = ‘$key‘ AND Expires > ‘" . date("Y-m-d H:i:s")."‘";         $qid = mysql_query($qry, $SESS_DBH);     }     return $qid; } function sess_destroy($key) {     global $SESS_DBH;     $qry = "DELETE FROM sessions WHERE SessionId = ‘$key‘";     $qid = mysql_query($qry, $SESS_DBH);     return $qid; } function sess_gc($maxlifetime) {     global $SESS_DBH;     $qry = "DELETE FROM sessions WHERE Expires < ‘" . date("Y-m-d H:i:s")."‘";     $qid = mysql_query($qry, $SESS_DBH);     return mysql_affected_rows($SESS_DBH); } session_set_save_handler( "sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc"); session_start();

  

至于修改作用域 直接在php网站的配置里修改就行,其他的php.ini的修改网上多的是。

 

 后续产生的问题

Asp.net 创建的session信息 ,php能读能写。Php创建的session  ASP.NET 在没有创建过Session 的时候不能读取。仅当Asp.Net的程序创建过 Session后,Php 修改过的内容才会生效。

 

这个问题产生的原因 是ASP.Net 的Session产生机制的问题,页面请求Asp.net并不会马上创建Session和读取Cookie 的SessionID去查找Session

解决这个问题又有多种方案,而我选用的是 最简单的一种 只用 Asp.net的登陆程序做入口。