会话在同一服务器上的多个域上共享
我听说在同一服务器上跨多个域共享会话的最佳方法是使用自定义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)
);
您无法从一个域中读取cookie其他领域。这是浏览器中实现的一项安全措施。使用会话数据库可让多个服务器在同一个域上共享会话,但不允许同一服务器上的多个域共享会话。
如果你想共享域之间的会话,你需要当您切换域,实现某种形式的会话转移的方法。最简单的方法是将会话ID作为GET参数从一个域的页面传递到另一个域的页面。然后,在另一个域上,您将选取会话ID并使用该ID创建新会话。
虽然这是一个简单的方法,但它不是非常安全并且会话劫持。更好的方法是使用数据库创建一个记录,其中包含会话标识,设置一个短暂的超时时间,并将该记录的标识传递给其他域。其他域会从数据库中选取记录并与之建立会话。如果数据库中的记录已过期,它将不会接收会话。这将为会话劫持提供更好的保护。
如果你想共享域之间的会话,你需要在切换域时实施某种会话传输方法。
是的,我已经用这种方法来获得以前的会话ID ..它不工作..如果新的域使用相同的ID,它会删除以前的域的ID –
2011-01-21 14:00:05
@Eric Petroelje,您的解决方案是伟大的,谢谢 – 2012-11-27 02:46:24
你真的应该看看SSO(单点登录)。 SSO的一个选择是使用OpenID(在SO上使用),使用它将使您的生活变得更加轻松。
这里有一篇文章就可以了:http://devzone.zend.com/article/3581
饼干和自己的知名度是一个问题。访问新网站的浏览器不会将旧网站的会话ID发送到服务器。
我觉得你的阅读()不使用您提供的会话ID的SSID参数,但在浏览器与此域没有会话,系统将生成一个新的ID为$ ID。看看数据库中是否存在$ _REQUEST ['ssid']。
自定义会话处理程序可能对这项工作有点大。您可以检查会话数据库中是否存在$ _REQUEST ['ssid'],并用它重写$ _SESSION。
我想知道如果任何人都可以给我的方法的一些建议同一服务器(同一个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被启用。
想法?
这是session_name()
目的。为每个应用程序的会话分配一个不同的名称以避免$_SESSION
键之间的冲突。该名称将用作会话cookie的名称,因此虽然两个会话cookie都将传递给两个应用程序,但只有与应用程序的session_name()
匹配的那个将用于填充$_SESSION
。
// App 1
session_name('app1');
session_start();
// App 2
session_name('app2');
session_start();
我的事,答案就在这里: http://stackoverflow.com/questions/9317595/maintaining-session-variables-across-subdomains – haldyr 2012-11-08 09:16:10