在同一服务器上跨多个域的会话共享

时间:2011-01-21 13:27:48

标签: php

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

但是在我尝试之后,当我尝试从不同的域读取cookie值时,即使使用SAME DATABASE ON 1 SERVER的自定义php会话处理程序也无法共享会话。

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

P.S。要获取以前的会话ID,我使用以下链接:newdomain.com/?sid = [SERVION_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)
);

5 个答案:

答案 0 :(得分:11)

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

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

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

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

以下是一篇文章:http://devzone.zend.com/article/3581

答案 3 :(得分:0)

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

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

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

答案 4 :(得分: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';
}

然后在每个网站上我都有一个名为'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';
    }
}

使用text / css链接是个好主意吗? 我想,即使Javascript或图像被禁用,也总会调用它?

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

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

思想?