dede与discuz如何实现双向同步登录?

99ANYc3cd6
预计阅读时长 30 分钟
位置: 首页 DEDE建站 正文

核心原理

双向同步登录的核心思想是:让两个独立的用户系统共享同一个用户身份验证(登录/登出)的“状态”。

dede discuz 双向同步登录
(图片来源网络,侵删)

由于 DedeCMS 和 Discuz! 是两个独立的程序,它们各自有自己的用户数据库表和 Session 管理机制,直接让它们共享 Session 是不现实的,因此最常用也是最可靠的方法是通过 Cookie 和数据库联动来实现。

基本流程如下:

  1. 用户在 A 系统登录

    • A 系统验证用户名和密码。
    • A 系统在自己的数据库中更新该用户的登录状态(将 dede_member 表中的 logintime 更新为当前时间)。
    • A 系统向用户的浏览器写入一个特殊的、加密的 Cookie(dede_auth)。
  2. A 系统触发 B 系统登录

    dede discuz 双向同步登录
    (图片来源网络,侵删)
    • A 系统在成功写入自己的 Cookie 后,会立即通过 HTTP 请求(通常是 file_get_contentscurl)去访问 B 系统的一个“同步登录接口”页面。
    • 这个请求会携带用户的唯一标识(如 uid)。
    • B 系统的“同步登录接口”接收到请求后,验证请求的合法性(检查来源域名、验证 uid 是否有效)。
    • 验证通过后,B 系统模拟该用户登录,更新自己数据库中的用户登录状态,并向浏览器写入 B 系统自己的登录 Cookie(Discuz_auth)。
  3. 反向流程(B -> A)

    当用户在 B 系统登录或登出时,B 系统会以同样的方式去触发 A 系统的同步登录/登出接口。

图示说明:

[用户] --登录--> [DedeCMS]
       1. DedeCMS 验证用户,设置自己的 Cookie
       2. DedeCMS 调用 Discuz! 的同步登录接口
       3. Discuz! 接口接收请求,模拟登录,设置自己的 Cookie
       4. 用户被重定向到目标页面,此时两个系统都已登录
[用户] --退出--> [Discuz!]
       1. Discuz! 清除自己的 Cookie
       2. Discuz! 调用 DedeCMS 的同步登出接口
       3. DedeCMS 接口接收请求,清除登录状态
       4. 用户被重定向,两个系统都已登出

实现步骤(以 DedeCMS V5.7 + Discuz! X3.4 为例)

在开始之前,请务必备份你的数据库和网站文件!

第 1 步:统一用户表(可选但推荐)

为了数据一致性,最理想的情况是让两个系统共享同一个用户表,但这通常需要复杂的二次开发,且两个系统的用户字段结构不同,实现难度较大。

对于大多数用户来说,维持两个独立的用户表,但通过程序同步数据是更常见的选择,我们这里就按照这个思路来讲解。

第 2 步:在 Discuz! 中创建同步登录 API 文件

这个文件将作为 DedeCMS 调用 Discuz! 的入口。

  1. 在 Discuz! 的根目录下(bbs/),创建一个新文件,命名为 uc.php
  2. 将以下代码复制到 uc.php 文件中:
<?php
/**
 * Discuz! 同步登录接口
 * 由 DedeCMS 调用,实现 Discuz! 侧的登录
 */
// 定义 Discuz! 根目录,请确保路径正确
define('CURSCRIPT', 'uc');
define('IN_DISCUZ', true);
define('UC_CLIENT_VERSION', '1.0.0'); // 版本号,可自定义
define('UC_CLIENT_RELEASE', '20121112'); // 发布日期,可自定义
// 引入 Discuz! 的核心配置文件
require_once './config/config_global.php'; // 注意路径,根据你的目录结构调整
require_once './source/class/class_core.php';
// 初始化 Discuz! 数据库对象
$discuz = C::app();
// 关闭 Discuz! 的错误提示,防止 API 调用时输出 HTML
$discuz->init_cron = false;
$discuz->init_session = false;
$discuz->init();
// 引入同步登录相关的函数库
require_once './source/function/function_core.php';
require_once './source/function/function_member.php';
// --- 核心逻辑 ---
// 检查请求方式,只允许 POST 请求
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
    exit('Request Method Error');
}
// 获取 DedeCMS 传递过来的用户ID
$uid = intval($_POST['uid']);
if (empty($uid)) {
    exit('UID is empty');
}
// --- 安全性校验(非常重要!) ---
// 你可以在这里增加一个密钥验证,防止被恶意调用
// DedeCMS 调用时传递一个 $key = md5('your_secret_key' . $uid);
// 然后在这里验证 $key 是否与 $_POST['key'] 相等
// if ($_POST['key'] !== md5('your_secret_key' . $uid)) {
//     exit('Authentication failed');
// }
// -------------------------
// 调用 Discuz! 内部函数,模拟用户登录
// synlogin($uid) 会自动设置 Discuz! 的 Cookie 并输出 JavaScript 代码
// 我们需要捕获这个输出,然后执行它
ob_start();
synlogin($uid);
$script = ob_get_contents();
ob_end_clean();
// 输出 JavaScript 代码,由 DedeCMS 页面执行
echo $script;
?>

代码解释:

  • 这个文件首先加载了 Discuz! 的核心环境和配置。
  • 它接收一个 POST 请求,参数是 uid(DedeCMS 中的用户ID)。
  • 安全性:上面的代码中留了一个安全校验的注释框,强烈建议你实现这个密钥校验,否则任何知道这个接口的人都能模拟登录你论坛的任意用户。
  • synlogin($uid) 是 Discuz! 提供的内部函数,它会生成一段 JavaScript 代码,这段代码的作用就是设置浏览器的 Discuz! 登录 Cookie。
  • 我们用 ob_start()ob_get_contents() 捕获这段 JS 代码,echo 出来。

第 3 步:修改 DedeCMS 的登录处理文件

我们需要让 DedeCMS 在用户成功登录后,去调用刚刚创建的 uc.php

  1. 找到 DedeCMS 的会员登录处理文件,通常位于 /member/login.php
  2. 在该文件中,找到登录成功后的代码段,在 if($rs) 里面,在 ShowMsg() 函数之前,添加如下代码:
// 在 DedeCMS /member/login.php 中添加
// ... 原有代码 ...
if($rs) {
    // 原有的登录成功逻辑
    $dsql->ExecuteNoneQuery("UPDATE `dede_member` SET `logintime`='".time()."', `loginip`='".GetIP()."' WHERE `mid`='".$rs['mid']."';");
    $safecv = md5($rs['pwd'].$rs['secques']);
    $loginsum = md5($rs['user'].$rs['pwd'].$cfg_cookie_encode);
    // 设置 DedeCMS 自身的 Cookie
    SetCookie("DedeUserID", $rs['mid'], time()+3600*24*30, '/');
    SetCookie("DedeLoginTime", time(), time()+3600*24*30, '/');
    SetCookie("DedeLoginTime", time(), time()+3600*24*30, '/');
    SetCookie("dede_logintime", time(), time()+3600*24*30, '/');
    SetCookie("dede_loginuser", $rs['user'], time()+3600*24*30, '/');
    SetCookie("dede_loginpwd", $safecv, time()+3600*24*30, '/');
    // --- 新增:同步登录到 Discuz! ---
    $bbs_url = 'http://你的域名.com/bbs/'; // <-- 修改为你的 Discuz! 论坛地址
    $sync_api_url = $bbs_url . 'uc.php';
    $uid = $rs['mid']; // DedeCMS 的用户ID
    // 使用 file_get_contents 或 curl 调用 Discuz! 的同步登录接口
    $post_data = array(
        'uid' => $uid,
        // 'key' => md5('your_secret_key' . $uid) // 如果你设置了密钥校验,请加上这一行
    );
    $context = stream_context_create(array(
        'http' => array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/x-www-form-urlencoded',
            'content' => http_build_query($post_data),
            'timeout' => 10 // 设置超时,避免用户等待
        )
    ));
    // 调用接口,并捕获返回的 JS 代码
    $javascript_code = @file_get_contents($sync_api_url, false, $context);
    // 将返回的 JS 代码输出到页面,由浏览器执行
    // 这通常在 ShowMsg 之前,或者在页面的 footer 中执行
    // 为了简单,我们可以直接 echo,但更好的方式是存入一个变量,在模板中输出
    echo $javascript_code; 
    // --- 新增结束 ---
    // 原有的登录成功提示
    ShowMsg('成功登录,正在进入...',$gourl,0,2000);
    exit();
}

代码解释:

  • 我们获取了当前登录用户的 mid(DedeCMS 的用户ID)。
  • 构造了调用 Discuz! uc.php 的 URL 和 POST 数据。
  • 使用 file_get_contents 发送了一个 POST 请求到 Discuz! 的接口。
  • Discuz! 的接口会返回一段 JS 代码,我们直接 echo 它,当 DedeCMS 的登录页面加载时,这段 JS 也会被执行,从而在浏览器中设置 Discuz! 的登录 Cookie。

第 4 步:实现反向同步(Discuz! -> DedeCMS)

这个过程和上面是镜像的。

  1. 在 DedeCMS 中创建同步登录接口

    • 在 DedeCMS 根目录()创建一个文件,api/dede_sync.php
    • 写入一个 PHP 脚本,该脚本接收 uid,验证后,模拟 DedeCMS 的登录(通常也是输出一段 JS 代码来设置 DedeCMS 的 Cookie)。
  2. 修改 Discuz! 的登录处理文件

    • 找到 Discuz! 的登录处理文件 /source/class/class_member.php 中的 login() 方法,或者更简单的方式是修改模板 /template/default/login/login.htm 在登录成功后通过 JavaScript 发起一个请求。
    • 在 Discuz! 登录成功后,调用 DedeCMS 的 dede_sync.php 接口,传递 Discuz! 的 uid(注意:这里需要建立一个 DedeCMS的uid和Discuz!的uid的映射关系,最简单的是让它们相同,或者通过一个中间表关联)。

注意:由于 Discuz! 的登录流程更复杂(涉及 AJAX 请求等),直接修改其核心文件风险较高,一个更稳妥的方法是修改 Discuz! 的登录模板,在登录成功的 JavaScript 回调中,加入一个 AJAX 请求去调用 DedeCMS 的接口。


同步登出

同步登出的原理和登录完全一样,只是流程相反,并且通常是清除 Cookie。

  1. 在 Discuz! 中创建同步登出接口 (uc.php 可以扩展,或新建 uc_logout.php):

    • 这个接口调用 Discuz! 的 synlogout() 函数,该函数会生成一段清除 Discuz! 登录 Cookie 的 JS 代码。
  2. 在 DedeCMS 中创建同步登出接口 (dede_sync.php 或新建 dede_logout.php):

    这个接口生成一段清除 DedeCMS 登录 Cookie 的 JS 代码。

  3. 互相调用

    • 当用户在 DedeCMS 登出时,调用 Discuz! 的同步登出接口。
    • 当用户在 Discuz! 登出时,调用 DedeCMS 的同步登出接口。

重要注意事项与常见问题

  1. 安全性是重中之重

    • 必须为你的同步 API 接口设置密钥验证,防止被恶意调用,任何知道你接口地址的人,都可以伪造请求登录你的网站。
    • 可以使用 $secret_key = 'your_long_random_string';$key = md5($secret_key . $uid) 的方式传递和验证。
  2. 用户 ID 映射问题

    • 这是最容易出错的地方,DedeCMS 的用户 ID 在 dede_member 表的 mid 字段,Discuz! 的用户 ID 在 pre_common_member 表的 uid 字段。
    • 最佳实践:在用户注册时,让两个系统生成相同的用户 ID,这需要修改 DedeCMS 和 Discuz! 的注册流程,让它们共享一个 ID 生成器(使用数据库的自增 ID,但跨库操作很麻烦)。
    • 次优实践:建立一个映射表 dede_bbs_map,包含 dede_uidbbs_uid 字段,在用户注册时,同时向两个系统注册,并记录下这个映射关系,同步登录时,通过这个映射表找到对方的用户 ID。
  3. Cookie 作用域和路径

    • 确保 Cookie 的作用域(domain)和路径(path)设置正确,使得 a.combbs.a.com 能够互相读写 Cookie,通常设置为 .a.com 即可。
  4. 错误处理和超时

    同步请求是异步的,如果其中一个系统挂了,不应该影响另一个系统的登录,在调用 API 时,设置一个合理的超时时间(如 1-2 秒),如果超时,就忽略错误,只保证当前系统的登录成功。

  5. 版本兼容性

    不同版本的 DedeCMS 和 Discuz!,其文件路径、函数名、数据库结构可能不同,以上代码是基于较老版本的,如果你使用的是最新版本(如 DedeCMS 5.7sp2, Discuz! X3.5),可能需要根据实际情况调整文件路径和函数调用。

  6. 性能影响

    每次登录都会发起一次跨域 HTTP 请求,会增加服务器负担和用户登录的延迟,确保你的服务器性能足够,API 接口处理高效。

更高级的方案:单点登录

双向同步登录是一种“伪”单点登录,因为用户最终还是需要在一处登录,然后系统去同步另一处。

真正的单点登录流程如下:

  1. 用户访问 A 系统,发现未登录。
  2. A 系统重定向到统一的认证中心。
  3. 用户在认证中心登录。
  4. 认证中心验证成功后,分别向 A 系统和 B 系统发放“票据”(Ticket)。
  5. A 系统和 B 系统收到票据后,向认证中心验证票据的有效性。
  6. 验证通过后,用户就在 A 和 B 系统中同时处于登录状态。

SSO 实现起来更复杂,通常需要引入一个专门的认证服务,但对于 DedeCMS + Discuz! 这种架构,自己实现 SSO 难度很大,双向同步登录仍然是目前最主流、最实用的解决方案。

希望这份详细的指南能帮助你成功实现 DedeCMS 和 Discuz! 的双向同步登录!

-- 展开阅读全文 --
头像
Win10 C语言开发环境如何配置与使用?
« 上一篇 2025-12-11
织梦平台下web站点如何高效创建与管理?
下一篇 » 2025-12-11

相关文章

取消
微信二维码
支付宝二维码

目录[+]