在 2 个 WordPress 上共享用户安装在同一台服务器上的 2 个子域中

Posted

技术标签:

【中文标题】在 2 个 WordPress 上共享用户安装在同一台服务器上的 2 个子域中【英文标题】:sharing user on 2 WordPress installs in 2 sub domains on same server 【发布时间】:2015-09-06 07:26:21 【问题描述】:

我在 test1.abc.comtest2.abc.com 等 2 个不同的子域中有 2 个 WordPress 网站。两个站点都激活了 wp-require 插件,只有登录用户才能看到该站点。我们想要创建一个系统,如果用户登录到一个站点,他应该自动登录到另一个站点。

我的尝试:

经过一番搜索,我知道我需要为两个站点使用一个数据库。所以我做了这些步骤:

我已经下载了 test2.abc.com 站点的整个数据库并将所有前缀 wp_ 更改为 wpmo_,在整个数据库中替换它并将其上传到第一个站点的数据库中。 我在第二个站点的 wp-config.php 中添加了这两行,以定义第二个站点应该使用第一个站点的用户表而不是它自己的。

define('CUSTOM_USERMETA_TABLE', 'wp_usermeta');
define('CUSTOM_USER_TABLE', 'wp_users');

现在,第二个站点正在使用第一个站点的用户,我可以通过第一个站点的用户详细信息登录到第二个站点。

下一个问题是 cookie,所以我在两个站点的 wp-config 中添加了这些行。

define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEPATH', '/');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');

现在我登录了 test1.abc.com,当我转到 test2.abc.com 时,它要求我登录。这意味着 cookie 不会从第一个站点传递到第二个站点。但是,我尝试打印 $_COOKIE,它给了我相同的加密值,但用户仍然没有在第二个站点上自动登录。当我回到第一个站点时,它也会自动注销。我觉得这两个网站在 cookie 上都有某种关联,我很接近但仍未达到自动登录第二个网站的目标。

有什么帮助吗?

解决方案:

在 Mikk3lRo 和其他人的帮助下,我设法解决了这个问题。我正在为面临同样问题的任何人发布解决方案。 在这里你可以找到分步指南:

第 1 步: 使用一个数据库进行两次安装,通过在安装时间使用 2 个不同的前缀来安装 2 个 wp。

步骤 2: 确保随机生成的密钥和盐在两个 wp-config.php 文件中也相同。

第 3 步:将这两行粘贴到第二个站点的 wp-config.php 中。

//Share user tables
define('CUSTOM_USER_META_TABLE', 'SITE1_PREFIX_usermeta');
define('CUSTOM_USER_TABLE', 'SITE1_PREFIX_users');

第 4 步: 与这些行共享 cookie。 (写在 wp-config.php 中)

//Share cookies
define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');

第 5 步:现在您可以在登录第一个站点时自动登录第二个站点。但是您会在第二个站点上显示错误消息“您无权访问此页面”,这是一件好事。

第 6 步: 原因是,WordPress 会检查用户权限(wp-includes/capabilities.php),因此您可以直接在数据库中添加此功能(如果您只有少数用户)或为此编写插件。 @Mikk3lRo 在 cmets 中为此写了一个插件,很好。

谢谢

【问题讨论】:

你试过define('COOKIE_DOMAIN', false);吗? 刚试过,没有运气。好吧,我认为 COOKIE_DOMAIN 应该在两个 wp 安装中都很常见。 你有什么理由不接受我的回答吗? 【参考方案1】:

好的 - 你已经很接近了,但还有一些事情要做。

所有要求如下:

使用不同的前缀共享同一个数据库 - 你已经做到了。从这里我假设前缀是wp1_wp2_等等。 分享wp1_userswp1_usermeta 表 - 你已经这样做了 - 实际上,如果你正确拼写常量名称,你就会克服这个障碍......它是CUSTOM_USER_META_TABLE(比什么多一个下划线你有) 使用共同的 COOKIE_DOMAINCOOKIEHASH 在子域之间共享 cookie - 你已经做到了 确保(通常)随机生成的密钥和盐也是相同的 - 你没有写你已经这样做了,但从你的结果来看,我认为你有或者你的密钥是空的(这是不好,但会起作用) 确保共享 usermeta 表中每个站点的每个用户都有一个 prefix_capabilities 条目 - 我认为您没有这样做,只是因为您还没有达到您意识到它的地步必要的。

完整解决方案:

这在wp-config.php:

//Share user tables
define('CUSTOM_USER_META_TABLE', 'wp1_usermeta');
define('CUSTOM_USER_TABLE', 'wp1_users');

//Share cookies
define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');

/**
 * In my case these are not needed - but they may well be if one
 * of the installs is located in a sub-folder. I have not tested
 * this theory though.
 */
//define('COOKIEPATH', '/');
//define('SITECOOKIEPATH', '/');
//define('ADMIN_COOKIE_PATH', '/wp-admin');

//These all need to be identical
define('AUTH_KEY', 'this should be random');
define('SECURE_AUTH_KEY', 'this should also be a random string');
define('LOGGED_IN_KEY', 'one more random string');
define('AUTH_SALT', 'oh my - so many random strings');
define('SECURE_AUTH_SALT', 'salt, salt, salt and no eggs');
define('LOGGED_IN_SALT', 'this is sooooo random');

/**
 * These do not need to be shared - in fact they probably shouldn't be
 * - if they are you could (in theory) do actions on one site that was
 * intended for the other - probably not a very big concern in reality
 */
define('NONCE_KEY', 'these should be random too, but can differ');
define('NONCE_SALT', 'one site has one, the other another');

这足以让您在两个网站上都登录 - 但列表中还剩下最后一个烦人的项目符号。

问题是您的权限(“功能”)仅在其中一个站点上有效,因为 meta_key 以该站点的表前缀为前缀。如果您稍微搜索一下,您会发现很多解决方案建议修改 wp-includes/capabilities.php 以仅使用公共前缀 - 我强烈建议您不要这样做! (不是出于安全原因,而是因为您需要在每次更新后制作这个补丁/破解......而且修改核心文件只是非常糟糕的做法)

为了解决这个问题,您需要复制wp1_usermeta 表中的wp1_capabilities 行(针对每个用户!),给它一个新的umeta_id 并将表前缀wp1_ 替换为wp2_ meta_key 列。您需要为每个站点执行此操作,因此您有一排是 meta_key wp1_capabilities,一排是 wp2_capabilities,依此类推。

如果您和您的朋友是唯一会登录网站的用户,那么只需通过 phpMyAdmin 或其他方式手动完成 - 如果您需要它动态工作,那么应该很有可能用一个小插件自动化(见下面的编辑)。

我一直讨厌这种设计 - 表格前缀在表格行中没有任何意义!我认为多站点安装需要它,但我确信会有其他(更好的)方法来解决它......

更新:使用户角色在所有站点之间保持同步的插件

这个简单的插件将在创建或编辑用户时复制并保持usermeta 表中所需的行更新。

值得注意的是,它可能不适用于多站点安装,因为它们具有一些特殊的功能/角色。我没有测试过。

它可能需要针对特定​​用例进行改进(请发表评论),但对于我只包含少数用户的有限测试用例,它可以很好地完成工作。对于拥有数千名用户的站点来说,这将是低效的,但由于它仅在用户被修改时运行,并且仅在需要时才进行更新,我怀疑这将是一个主要问题。然而,它应该相对容易适应只读取和修改刚刚添加/编辑的用户。不过,这会使初始设置复杂一些,因为预先存在的用户不会在第一次运行时自动复制。

创建文件夹wp-content/plugins/duplicate-caps 并将以下内容放入duplicate-caps.php - 并且不要忘记在wordpress 管理员中的plugins 下激活。它需要安装在所有站点上。

<?php
/*
Plugin Name: Duplicate Caps
Plugin URI: 
Description: Tiny plugin to duplicate capabilities in a setup where users (and user tables) are shared across more than one install
Author: Mikk3lRo
Version: 0.1
Author URI: 
*/
$dummy = new duplicate_caps();
class duplicate_caps 
    function __construct() 
        add_action('updated_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
        add_action('added_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
        add_action('deleted_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
    
    function update_prefixed_caps($mid, $object_id) 
        /**
         * Note that $object_id contains the id of the user that was
         * just changed.
         * On a site with many users it would make sense to only
         * get and set information regarding the just-changed user
         * Currently this function corrects roles for all users
         * making sure pre-existing users are duplicated, and keeping
         * the table in sync.
         */
        global $wpdb;
        //Quick and dirty - get all *capabilities rows for all users
        $sql = "SELECT * FROM $wpdb->usermeta WHERE `meta_key` LIKE '%capabilities'";
        $results = $wpdb->get_results($sql) or die(mysql_error());

        //Will hold all prefixes (always include our own)
        $prefixes = array($wpdb->prefix);

        //Will grab the existing role for each prefix
        $user_roles = array();

        //Loop our results
        foreach ($results as $result) 
            //Make sure the meta_key looks right, and grab the prefix
            if (preg_match('#^(.*)capabilities$#', $result->meta_key, $matches)) 
                $prefix = $matches[1];

                // Collect prefixes
                $prefixes[] = $prefix;

                //Note the entire row for later use
                $user_roles[$result->user_id][$prefix] = $result;
            
        

        //Make sure we only have one of each
        $prefixes = array_unique($prefixes);

        //Loop through the users we found
        foreach ($user_roles as $user_id => $existing_prefixes) 
            if (!isset($existing_prefixes[$wpdb->prefix])) 
                //User was probably just deleted - all rows are deleted by
                //wordpress though, so no cleanup for us :)
             else 
                //We want all prefixes to obey us (we just created or changed
                //the user, so we want that to affect all sites)
                $desired_role = $existing_prefixes[$wpdb->prefix]->meta_value;

                //Loop through all prefixes
                foreach ($prefixes as $prefix) 
                    //Data to be inserted / updated
                    $cap_data = array(
                        'user_id' => $user_id,
                        'meta_key' => $prefix . 'capabilities',
                        'meta_value' => $desired_role
                    );

                    //If the prefix doesn't exist for this user
                    if (!in_array($prefix, array_keys($existing_prefixes))) 
                        //Actually insert it (user was probably just created)
                        $wpdb->insert($wpdb->usermeta, $cap_data, array('%d', '%s', '%s'));
                     else if ($desired_role !== $existing_prefixes[$prefix]->meta_value) 
                        //Update it if not already correct (user was probably just edited)
                        $cap_data['umeta_id'] = $existing_prefixes[$prefix]->umeta_id;
                        $wpdb->replace($wpdb->usermeta, $cap_data, array('%d', '%s', '%s', '%d'));
                    
                
            
        
    

【讨论】:

仍然没有工作,我做了同样的事情:它是 CUSTOM_USER_META_TABLE(比你所拥有的多一个下划线):完成,确保(通常)随机生成的密钥和盐也是相同的:是的,他们是。我稍后会解决功能问题,但它仍然不会在第二个站点上给我功能错误。我以用户身份登录第一个站点,转到新选项卡中的第二个站点,仍然希望我登录:(。如果我收到该错误消息,我将解决功能问题。 我有这个工作在你描述的确切设置上。两个新的 wordpress 安装,每个都在自己的子域上。登录到其中一个,您在另一个上登录。 “相同”到底是什么意思? 不知道我做错了什么。我在 2 个子域(2 个文件夹)上安装了 2 个最新的 wp。共享相同的键和盐字符串、相同的用户和用户元表、相同的 cookie 域和哈希键。我登录到 test1.abc.com,然后在新选项卡(如 test2.abc.com/wp-admin)中打开 test2.abc.com,它仍然要求我登录。 我刚刚在第二个站点上收到权限错误消息,我通过删除此行进行检查,define('COOKIEPATH', '/');让我解决能力问题,我想它会在此之后完成。 嗨@Mikk3lRo,感谢您的帮助。我现在完成了。赏金是你的。快乐编码!【参考方案2】:

我认为定义 cookie 不足以登录 wp 网站。

所以我的解决方案是,创建一个插件来限制那些没有登录到其中一个站点的人的访问。 当用户登录到其中一个站点时设置一个 cookie。 当用户查看网站时。检查cookie值,并重定向或返回站点。

示例代码:

 add_action('wp_login','prefix_set_cookie'); //when someone logged in this call the set_cookie function

 function prefix_set_cookie()
    setcookie('hashed_cookie','my_value'); //set the cookie

 

 //call check_cookie function when wordpress site loads
 add_action('wp','check_cookie');

 function check_cookie()
    //check the cookie value and view the website
    if(isset($_COOKIE['hashed_cookie'] ))
        if($_COOKIE['hashed_cookie'] == 'my_value')
         return;            
        else
            die("no access please login <a href='your login link'>LINK</a>");
        
    
 

这个插件的主要缺点是安全性差。任何人手动创建此 cookie。所以它的安全性很高,不要使用它。尽量对 cookie 进行哈希处理,这样就不容易手动创建。

(如果您想要插件的完整代码,请放在某处)

更新(完整插件):

<?php
/*
Plugin Name: Restrict Access
Author: Pasindu Jayawardane
Description: This Plugin Restrict Access to the Site without login
Author URI: https://www.facebook.com/pj.pasiya
*/

 $key = hash('md5','restrict_access');
 $value = hash('md5','true');

 add_action('wp_login','es_set_cookie');

 function es_set_cookie()
    global $key, $value;

    setcookie($key, $value ,time()+3600);

 

 add_action('wp_logout','es_remove_cookie');

 function es_remove_cookie()
    global $key, $value;

    setcookie($key, $value ,time()-3600);
 

 add_action('wp','es_check_cookie');

 function es_check_cookie()
    global $key, $value;

    if(isset($_COOKIE[$key] ))
        if($_COOKIE[$key] == $value)
         return;            
        else
            ?>
            <h1 class="alert alert-danger">
                This Website is Protected! <small>You Must Login to See the Website</small>
            </h1>
            <p class="ra-login"> <a href="<?php echo wp_login_url(); ?>"> Login </a> <p>
        <?php

            die();
        
    else
        ?>
        <h1 class="alert alert-danger">
            This Website is Protected! <small>You Must Login to See the Website</small>
        </h1>
        <p class="ra-login"> <a href="<?php echo wp_login_url(); ?>"> Login </a> <p>
        <?php

        die();
    
 

转到您的 wordpress 安装插件目录 (wp install folder->wp-content->plugins 并创建一个扩展名为 .php 的新文件 file-restrict.php 复制并粘贴此代码

对两个网站都这样做

转到 wordpress 插件并激活插件。 (两个网站)

一旦您登录其中一个站点,您就可以查看其中一个站点。一旦您注销一个站点,它会给出一条消息,其中包含登录该站点的链接。

(激活后只需注销并登录该站点)

我也会将代码通过电子邮件发送给您。

【讨论】:

感谢您的回复。看起来它可以工作,你可以给我任何帮助 gaurav.tyagi@techstriker.com 赏金将是你的,一旦我完成了。 好的,请稍等。 我不明白这是如何解决问题的。它只是向尚未登录的用户显示一条消息以登录(在他们所在的任何站点上)。我理解的想法是只保护其中一个站点,并让人们只在另一个站点上登录 - 然后重定向回他们来自的站点 - 这在代码中没有任何位置,即使它确实像那样工作,用户实际上不会在未受保护的网站上登录 - 这意味着评论等只能匿名进行。它还会创建无效的 html(即 wp 钩子中的 die() 意味着没有 &lt;html&gt;&lt;body&gt;、样式表等)。 @Mikk3IRo 用户想在登录后查看网站,并限制谁没有登录网站,这就是 wp-require 添加 Restricted Site Access 插件。但他也想在登录第一个网站后查看第二个网站。如果您转到下一个站点,此插件允许用户登录到一个站点并查看内容。它存储 cookie,因此它也可以看到该网站。关于无效的 html。该网页会将消息编译为文本文件而不会出现任何错误。这个解决方案很简单,不需要任何第三方插件。但是这个插件不会自动登录到 wordpress 网站,只是允许他们观看 这就像我对 php refrer 所做的(也不是安全的方式),但这里有一个问题,我需要用户登录第二个站点(不仅能够看到)。原因是,用户会添加帖子并可以评论其他人的帖子。使用此代码,他们可以看到该站点,但实际上并未登录。【参考方案3】:

我相信对您来说最简单的解决方案是使用 WordPress 的单点登录 (SSO) 插件之一。

列出了大量的插件here。

您可以使用其中之一或基于其中之一进行身份验证。

另外还有multi-site,它可以让你创建一个站点网络,如果你决定创建一个多站点,那么请先阅读this。

【讨论】:

感谢您的回复,现在无法使用多站点,因为站点在不同的数据库上运行了很长时间。这些插件在我的情况下也没有用。我期待有关 Cookie 的一些答案。 你描述的功能是单点登录(SSO),你确定没有插件适合吗? 我做了,这似乎不可靠。插件有 1 分(满分 5 分)和床评论。 “这个脚本正在窃取你的 wordpress 和 whmcs 用户名密码哈希其他信息。不要使用它。”我的网站有数千个用户,不确定是否使用此插件。

以上是关于在 2 个 WordPress 上共享用户安装在同一台服务器上的 2 个子域中的主要内容,如果未能解决你的问题,请参考以下文章

在我的网站和 wordpress 博客之间共享会话

如何允许用户从 WordPress 网站下载内容

FileZilla-02

黄聪:Wordpress二级域名共享用户cookie出现错误解决方案及WP的Cookie机制

在以前的 mysql 安装上安装 wordpress。用户等

从另一个 wordpress 远程数据库中提取用户并显示