2011-01-21 159 views
6

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

但我试过后,甚至自定义php会话处理程序,使用相同数据库1服务器不能共享会话,当我尝试从不同的域读取cookie值。

这里是我的自定义会话处理程序,请检查或修复如果在这里丢失的东西。因为我已经尝试了一个礼拜了。不能得到它的工作

P.S.要获得以前的会话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) 
); 
+0

我的事,答案就在这里: http://stackoverflow.com/questions/9317595/maintaining-session-variables-across-subdomains – haldyr 2012-11-08 09:16:10

回答

11

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

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

虽然这是一个简单的方法,但它不是非常安全并且会话劫持。更好的方法是使用数据库创建一个记录,其中包含会话标识,设置一个短暂的超时时间,并将该记录的标识传递给其他域。其他域会从数据库中选取记录并与之建立会话。如果数据库中的记录已过期,它将不会接收会话。这将为会话劫持提供更好的保护。

+0

如果你想共享域之间的会话,你需要在切换域时实施某种会话传输方法。是的,我已经用这种方法来获得以前的会话ID ..它不工作..如果新的域使用相同的ID,它会删除以前的域的ID – 2011-01-21 14:00:05

+0

@Eric Petroelje,您的解决方案是伟大的,谢谢 – 2012-11-27 02:46:24

0

你真的应该看看SSO(单点登录)。 SSO的一个选择是使用OpenID(在SO上使用),使用它将使您的生活变得更加轻松。

这里有一篇文章就可以了:http://devzone.zend.com/article/3581

0

饼干和自己的知名度是一个问题。访问新网站的浏览器不会将旧网站的会话ID发送到服务器。

我觉得你的阅读()不使用您提供的会话ID的SSID参数,但在浏览器与此域没有会话,系统将生成一个新的ID为$ ID。看看数据库中是否存在$ _REQUEST ['ssid']。

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

0

我想知道如果任何人都可以给我的方法的一些建议同一服务器(同一个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'; 
} 

然后在每个站点我称它包含

<?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'; 
    } 
} 

“sso_set.php”文件使用文本/ css链接是个好主意吗? 我想这总是被称为即使Javascript或图像被禁用?

此代码基本上使得第一现场出我所有的网站,被用户打开的设置会话ID,然后将其传递到其他网站。

似乎工作得很好。 您第一次打开任何网站并将ID传递到网站时,您会稍微延迟。但是,你可以通过AJAX做到这一点,所以页面加载速度很快。但是,那么你依靠Javascript被启用。

想法?

1

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

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

// App 2 
session_name('app2'); 
session_start(); 
相关问题