具有多个域和子域的 PHP 身份验证

Posted

技术标签:

【中文标题】具有多个域和子域的 PHP 身份验证【英文标题】:PHP authentication with multiple domains and subdomains 【发布时间】:2011-05-04 17:59:21 【问题描述】:

我有一个主域:main.com,子域:test1.main.comtest2.main.com 和其他域one.comtwo.com

现在是这样完成的:

ini_set("session.cookie_domain", ".main.com");

$domain = 'main.com';

登录.php

$user = $db->query("SELECT id, login FROM users WHERE email=? AND password=?", 
array($email, $password), "rowassoc");

if($user)

  $_SESSION['user_id'] = $user['id'];
  $_SESSION['user_name'] = $user['login'];

  $time = 100000; 

  setcookie('email', $email, time() + $time, "/", "." . $domain);
  setcookie('password', $password, time() + $time, "/", "." . $domain);

  header('Location: http://' . $user['login'] . "." . $domain);
  exit;

在每个页面上添加:

if(!isset($_SESSION['user_id']))

  if(isset($_COOKIE['email']) && isset($_COOKIE['password']))
  
    $email = $_COOKIE['email'];
    $password = $_COOKIE['password'];

    $user = $db->query("SELECT id, login FROM users WHERE email=? AND password=?",
    array($email, $password), "rowassoc");

    if($user)
    
      $_SESSION['user_id'] = $user['id'];
      $_SESSION['user_name'] = $user['login'];
    
  

else

  $user = $db->query("SELECT id, login FROM users WHERE id=?", 
  array($_SESSION['user_id']), "rowassoc");


  if(!$user)
  
    setcookie('email', '', time() , "/", "." . $domain);
    setcookie('password', '', time() , "/", "." . $domain);
    unset($_SESSION['user_id']);

    session_destroy();
    setcookie("PHPSESSID","",time(), "/", "." . $domain);
  
  else
  
    $_SESSION['user_id'] = $user['id'];
    $_SESSION['user_name'] = $user['login'];
  

注销.php

if(isset($_SESSION['user_id']))

  setcookie('email', '', time() , "/", "." . $domain);
  setcookie('password', '', time() , "/", "." . $domain);
  unset($_SESSION['user_id']);
  unset($_SESSION['user_name']);

  session_destroy();
  setcookie("PHPSESSID","",time(), "/", "." . $domain);

  header('Location: /main');
  exit;

但它仅适用于域 main.com 及其子域 test1.main.comtest2.main.com

我需要以某种方式保存会话以及其他域one.comtwo.com

如何最好地进行安全认证,如果有解决方案,我真的很困惑,请举例说明。

【问题讨论】:

我们需要方式更多关于您想要完成的任务的详细信息。身份验证与不同的域有什么关系?请编辑您的问题以添加更多细节。 ***.com/questions/244008/… 的副本 哇!永远不要将密码存储在 cookie 或数据库表中。密码应由 PHPass 库散列存储。 我已经在另一个地方更正了这个问题 此处提出的 Ajax/JS 和 iframe 解决方案:***.com/q/4813498/1066234 也可在此处查看此示例:github.com/0k/multidomain-sso 【参考方案1】:

要让您的会话跨越多个域,您需要使用session_set_cookie_params()。有了它,您可以指定您的域。比如……

session_set_cookie_params(10000, "/", ".main.com");

这会将站点根目录下的所有文档以及 main.com 的所有子域的会话超时设置为 10,000 秒。

您应该先致电session_set_cookie_params(),然后再致电session_start()

【讨论】:

我也这样做了 ini_set("session.cookie_domain", ".main.com");但其他域(one.com、two.com)中的问题不是子域。 啊,我明白了。为此,您将不得不手动传递会话 ID,并且可能将此会话信息存储在某处。您不能在一个域上创建 cookie 并由另一个域读取。【参考方案2】:

据我所知,子域之间的跨会话很好,但它不会延续到一个全新的域。为此,您需要某种集中式数据方法或 API。

数据库方法:您必须创建一个远程 mysql 数据访问,以便 domain2.com 可以访问 domain1.com 上的数据库。执行登录时,不仅应该创建一个新会话,而且应该将唯一的登录令牌(具有到期时间)放入 mysql 数据库中。现在,对于从 domain1.com 到 domain2.com 的每个链接,您应该添加一个包含随机生成的会话 id 的 $_GET 变量(md5 散列即可)。 domain2.com 收到访问者后,将获取 $_GET 变量,通过 MySQL 数据库运行它以查找登录令牌,如果匹配,则认为该用户已登录(并且可能嵌入 $_COOKIE 作为很好地存储登录数据)。这将使登录可以在两个完全不同的域之间转移。

API 方法:您需要创建一个 API 方法,以便 domain1.com 可以响应来自授权域的外部请求,以在用户被转发时检索登录令牌。此方法还要求从 domain1.com 到 domain2.com 的所有链接都附加一个 $_GET 变量以传递唯一的会话哈希。然后在接收到访问者时,domain2.com 将对 domain1.com/userapi.php(或任何您称之为文件的文件)发出 curl() 请求,并且应根据数据库中的内容测试变量。

这是我能解释的最好的了。用代码写出来是一项重要的工作,所以我不能提交。但是从你的代码来看,你对 PHP 有很好的理解,所以我相信你会成功的!

祝你好运。

【讨论】:

Sweet... 如果您有任何其他问题,请在此处发表评论,我也有兴趣让它发挥作用。据我所知,第三方网站(完全不同的域)上的 Facebook 身份验证使用类似的 API 令牌方法。 同意,但建议 OP 找到现有的解决方案,而不是自己动手。众所周知,“我的第一个安全系统”容易受到攻击。 请告诉我现有的解决方案 真的可以t understand how to recieve my sessid or cookie or something from main domain. i tried send sessid on logining with img to all domains but i have so many domains, i cant明白 到目前为止,我还不知道现有的解决方案。我倾向于自己进行繁重的 PHP 编码,从头开始。我讨厌 Joomla/Drupal 等。为了安全起见,请使用您的常识 - 使用 mysql_real_escape_string() 函数防止 sql 注入,确保数据库上的令牌每 10 分钟左右自动过期,除非用户处于活动状态,在这种情况下在每次页面加载时,将令牌从当前活动状态再更新 10 分钟。确保令牌没有发送到任何电子邮件等,并且可能在每次从站点跳转到另一个站点时重新设置令牌哈希......并且不要忘记 md5() 命令!【参考方案3】:

但是如果用户直接访问域one.com,则one.com无法通过上面提到的正确答案知道用户是否登录,似乎必须使用一些额外的js,它是jsonP!我们让account.main.com/userLoginStat.php?callback=loginThisDomain来检查用户是否登录过main.com,如果有,js回调函数loginThisDomain做一些事情将用户自动登录到 one.com。

【讨论】:

以上是关于具有多个域和子域的 PHP 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

向具有不同域和基本身份验证的服务器发出 ajax POST 请求是不可能的吗?

通过多个 Laravel 5 安装跨子域共享身份验证会话

NTLM 身份验证 - 在 PHP 中获取 Windows 登录名、域和主机

子域和使用 laravel 进行身份验证

具有多个身份验证源的JWT令牌

MVC 身份 cookie 跨子域进行身份验证