【问题标题】:Session Share Across Multiple Domains On Same Server同一服务器上的多个域之间的会话共享
【发布时间】:2011-01-21 13:27:47
【问题描述】:

我听说在同一台服务器上跨多个域共享会话的最佳方法是使用自定义 php 会话处理程序。 (即,域名不同,如 abc.com、xyz.com 而是单个应用程序。)

但是在我尝试之后,当我尝试从不同域读取 cookie 值时,即使是在 1 个服务器上使用相同数据库的自定义 php 会话处理程序也无法共享会话。

这是我的自定义会话处理程序,如果此处缺少某些内容,请检查或修复。因为我已经尝试了一个星期了。不能让它工作

附:要获取以前的会话 ID,我使用以下链接:newdomain.com/?ssid=[SESSION_ID]


SESSION_INCLUDE.PHP

<?php 

// config 
$m_host = "localhost"; //MySQL Host 
$m_user = "db_user"; //MySQL User 
$m_pass = "db_pass"; //MySQL Pass 
$m_db   = "db_name"; //MySQL Database
$table  = "sess_data";

$session_expire = 600; // Session expire time, in seconds (minutes * 60 = seconds) 

$gc_probability = 100; // Probability that the garbage collection function will be called. 50% chance by default 

ini_set("session.gc_probability",$gc_probability); 

/* Open function; Opens/starts session 

   Opens a connection to the database and stays open until specifically closed 
   This function is called first and with each page load */ 

function open ($s,$n) // do not modify function parameters 
{ 
  global $session_connection, $m_host, $m_user, $m_pass, $m_db; 
  $session_connection = mysql_pconnect($m_host,$m_user,$m_pass); 
  mysql_select_db($m_db,$session_connection); 
  return true; 
} 

/* Read function; downloads data from repository to current session 

   Queries the mysql database, unencrypts data, and returns it. 
   This function is called after 'open' with each page load. */ 
function read ($id) // do not modify function parameters 
{ 
  global $session_connection,$session_read,$table; 
  $query = "SELECT data FROM `$table` WHERE id=\"{$id}\""; 
  $res = mysql_query($query,$session_connection); 
  if(mysql_num_rows($res) != 1) return ""; // must return string, not 'false' 
  else 
  { 
    $session_read = mysql_fetch_assoc($res); 
    $session_read["data"] = base64_decode($session_read["data"]); 
    return $session_read["data"]; 
  } 
} 
function write ($id,$data) // do not modify function parameters 
{ 
  if(!$data) { return false; } 
  global $session_connection, $session_read, $session_expire, $table; 
  $expire = time() + $session_expire; 
  $data = mysql_real_escape_string(base64_encode($data)); 
  if($session_read) $query = "UPDATE `$table` SET data=\"{$data}\", expire=\"{$expire}\" WHERE id=\"{$id}\""; 
  else $query = "INSERT INTO sess_data SET id=\"{$id}\", data=\"{$data}\", expire=\"{$expire}\""; 
  mysql_query($query,$session_connection); 
  return true; 
} 
function close () 
{ 
  global $session_connection; 
  mysql_close($session_connection); 
  return true; 
} 
function destroy ($id) // do not modify function parameters 
{ 
  global $session_connection,$table; 
  $query = "DELETE FROM `$table` WHERE id=\"{$id}\""; 
  mysql_query($query,$session_connection); 
  return true; 
}
function gc ($expire) 
{ 
  global $session_connection,$table; 
  $query = "DELETE FROM `$table` WHERE expire < ".time(); 
  mysql_query($query,$session_connection); 
}
// Set custom handlers 
session_set_save_handler ("open", "close", "read", "write", "destroy", "gc"); 

// Start session 
session_start(); 
?>




MySQL 数据库说明

create table sess_data (
id2 int not null auto_increment,
id text not null,
data text,
expire int not null,
primary key(id2)
);

【问题讨论】:

标签: php


【解决方案1】:

您无法从另一个域中的一个域读取 cookie。这是在浏览器中实现的安全性。使用会话数据库可以让多个服务器在同一域上共享会话,但不允许同一服务器上的多个域共享会话。

如果您想在域之间共享会话,则需要在切换域时实现某种会话传输方法。最简单的方法是将会话 ID 作为 GET 参数从一个域的页面传递到另一个域的页面。然后,在另一个域上,您将获取会话 ID 并使用该 ID 创建一个新会话。

虽然这是一种简单的方法,但它不是很安全,并且允许会话劫持。更好的方法是使用数据库创建一个包含会话 ID 的记录,在其上设置一个短暂的超时,然后将该记录的 ID 传递给另一个域。然后,另一个域将从数据库中获取记录并与之创建会话。如果数据库中的记录已过期,则不会获取会话。这将提供更好的保护,防止会话劫持。

【讨论】:

  • 如果要在域之间共享会话,则需要在切换域时实现某种会话转移方法。 是的,我用这种方法来获取以前的会话 id.. 它不起作用.. 如果新域使用相同的 id,它将删除以前域的 id
  • @Eric Petroelje,您的解决方案很棒,谢谢
【解决方案2】:

这就是session_name() 的目的。为每个应用程序的会话分配不同的名称以避免$_SESSION 键之间的冲突。该名称将用作会话 cookie 的名称,因此虽然两个会话 cookie 都将传递给两个应用程序,但只有与应用程序的 session_name() 匹配的一个将用于填充 $_SESSION。

// App 1
session_name('app1');
session_start();

// App 2
session_name('app2');
session_start();

【讨论】:

    【解决方案3】:

    您确实应该研究 SSO(单点登录)。 SSO 的一种选择是使用 OpenID(在 SO 上使用),使用它会让您的生活变得更轻松。

    这是一篇关于它的文章:http://devzone.zend.com/article/3581

    【讨论】:

      【解决方案4】:

      cookie 及其可见性是一个问题。访问新站点的浏览器不会将旧站点的会话 ID 发送到服务器。

      我认为您的 read() 没有使用您提供的 ssid 参数作为会话 id,但由于浏览器没有与该域的会话,系统会生成一个新 id 为 $id 的会话。查看数据库中是否存在 $_REQUEST['ssid']。

      自定义会话处理程序对于这项工作可能有点大。您可以检查会话数据库中是否存在 $_REQUEST['ssid'] 并用它重写 $_SESSION 。

      【讨论】:

      • 对不起,我认为问题不在于将会话 ID 传递给新域。因为它仍处于测试阶段,我只是使用 firefox 插件自己手动更改 cookie 值。所以没有问题随着cookie通过!
      【解决方案5】:

      我想知道是否有人可以就我在同一服务器(同一 cookie 存储文件夹)上的域之间共享会话的方法提出一些建议。

      在我所有网站的每个页面 HEAD 标记中,我调用以下 PHP 代码

      if(!isset($_SESSION['sso'])) {
          require_once('database.php');
          $sites = array('http://site1', 'http://site2');
          session_regenerate_id(); //Make new session id that will be shared
      
          $session_id = session_id();
          foreach($sites as $site) {
             if($site != CURRENT_SITE) {
                $sesh_key = md5(SALT.$site.$session_id);
                $database->insertSessionId($sesh_key, $session_id);
                $url = sprintf('%s/sso_set.php?k=%s', $site, $sesh_key);
                echo('<link type="text/css" rel="stylesheet" href="'.$url.'" />');
             }
          }
          $_SESSION['sso'] = 'SET';
      }
      

      然后在每个站点上我都有一个名为“sso_set.php”的文件,其中包含

      <?php
      session_start();
      if(!isset($_SESSION['sso'])) {
          require_once('database.php');
          $key = $_GET['k'];
          $session_id = $database->getSessionId($key);
          if($session_id) {
              session_destroy();
              session_id($session_id);
              session_start();
              $database->deleteSessionId($key);
              $_SESSION['sso'] = 'SET';
          }
      }
      

      使用文本/css 链接是个好主意吗? 我认为即使禁用了 Javascript 或图像也总是会调用它?

      这段代码基本上使用户打开的所有站点中的第一个站点设置会话 ID,然后将其传递给其他站点。

      似乎工作得很好。 第一次打开任何站点并将 ID 传递给站点时,您会稍有延迟。但是,您可以通过 AJAX 执行此操作,以便快速加载页面。但是,您需要启用 Javascript。

      想法?

      【讨论】:

        猜你喜欢
        • 2014-04-16
        • 2013-04-21
        • 2014-07-11
        • 2015-06-27
        • 2015-12-23
        • 1970-01-01
        • 2012-07-29
        • 2021-12-26
        相关资源
        最近更新 更多