首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Discuz 論壇免通行證同步登入實作代碼解析

     編輯:PHP 綜合知識

前言

Discuz 作為國內最流行的論壇系統,雖內建通行證機制,但實際項目中常需與自有用戶系統整合。本文介紹一種無需調用通行證介面、直接操作 Discuz 資料表實現同步登入的方法,核心在於正確生成 Discuz 識別的 Cookie。

核心原理

Discuz 登入狀態由 auth Cookie 決定,其值經 authcode() 函數加密,包含密碼雜湊、安全提問答案、用戶 UID 三項資訊。只要在我們的系統驗證用戶帳密正確後,按 Discuz 規則寫入相同格式的 Cookie,即可實現同步登入。

完整實作代碼

<?php
session_start();
define('NOROBOT', TRUE);
define('CURSCRIPT', 'logging');
require_once './include/common.inc.php';
require_once DISCUZ_ROOT.'./include/misc.func.php';

if($action == 'login') {
    $field = $loginfield == 'uid' ? 'uid' : 'username';
    
    // 安全碼檢查邏輯(略)
    $seccodecheck = substr(sprintf('%05b', $seccodestatus), -2, 1);
    if($seccodecheck && $seccodedata['loginfailedcount']) {
        $seccodecheck = $db->result($db->query("SELECT count(*) FROM {$tablepre}failedlogins WHERE ip='$onlineip' AND count>='$seccodedata[loginfailedcount]' AND $timestamp-lastupdate<=900"), 0);
    }
    
    $discuz_uid = 0;
    $discuz_user = $discuz_pw = $discuz_secques = $md5_password = '';
    $member = array();
    $loginperm = logincheck();
    if(!$loginperm) {
        showmessage('login_strike');
    }
    
    $secques = quescrypt($questionid, $answer);
    if(isset($loginauth)) {
        $field = 'username';
        $password = 'VERIFIED';
        list($username, $md5_password) = daddslashes(explode("\t", authcode($loginauth, 'DECODE')), 1);
    } else {
        $md5_password = md5($password);
        $password = preg_replace("/^(.{".round(strlen($password) / 4)."})(.+?)(.{".round(strlen($password) / 6)."})$/s", "\\1***\\3", $password);
    }
    
    // 查詢用戶資料
    $query = $db->query("SELECT m.uid AS discuz_uid, m.username AS discuz_user, m.password AS discuz_pw, m.secques AS discuz_secques,
        m.adminid, m.groupid, m.styleid AS styleidmem, m.lastvisit, m.lastpost, u.allowinvisible
        FROM {$tablepre}members m LEFT JOIN {$tablepre}usergroups u USING (groupid)
        WHERE m.$field='$username'");
    $member = $db->fetch_array($query);
    
    // 驗證密碼
    if($member['password'] != $md5_password) {
        echo "您輸入的用戶名或密碼錯誤!";
        exit();
    }
    
    // 登入成功,寫入 Cookie
    extract($member);
    $discuz_userss = $discuz_user;
    $discuz_user = addslashes($discuz_user);
    
    if(($allowinvisible && $loginmode == 'invisible') || $loginmode == 'normal') {
        $db->query("UPDATE {$tablepre}members SET invisible='".($loginmode == 'invisible' ? 1 : 0)."' WHERE uid='$member[discuz_uid]'", 'UNBUFFERED');
    }
    
    $styleid = intval(empty($_POST['styleid']) ? ($styleidmem ? $styleidmem : $_DCACHE['settings']['styleid']) : $_POST['styleid']);
    $cookietime = intval(isset($_POST['cookietime']) ? $_POST['cookietime'] : ($_DCOOKIE['cookietime'] ? $_DCOOKIE['cookietime'] : 0));
    dsetcookie('cookietime', $cookietime, 31536000);
    dsetcookie('auth', authcode("$discuz_pw\t$discuz_secques\t$discuz_uid", 'ENCODE'), $cookietime);
    
    $sessionexists = 0;
    updatesession(); // 更新論壇 USERPASS 數據
    echo "{'action':'true'}"; // 自定義返回數據
    print_r($_DSESSION);
    echo $discuz_userss;
}
?>

關鍵點解析

1. 必須引入的 Discuz 核心檔案

  • common.inc.php:初始化資料庫連線、全域變數、常用函數。
  • misc.func.php:包含 authcode()、dsetcookie()、quescrypt() 等關鍵函數。

2. 密碼驗證邏輯

Discuz 密碼存儲為 md5($password)。代碼中先將用戶提交的明文密碼進行 MD5 雜湊,再與資料庫 password 欄位比對。若一致,提取 uid、password(已加密)、secques 三項關鍵資訊。

3. Cookie 生成核心

dsetcookie('auth', authcode("$discuz_pw\t$discuz_secques\t$discuz_uid", 'ENCODE'), $cookietime);
  • $discuz_pw:資料庫中已 MD5 加密的密碼。
  • $discuz_secques:安全提問答案的加密值(未設定也需帶入)。
  • $discuz_uid:用戶唯一識別 ID。
  • 三者以 Tab 鍵 \t 分隔,經 authcode() 加密後寫入 Cookie。

4. 加密金鑰一致性

authcode() 函數內部使用常量 UC_KEY(或配置檔中的 $discuz_auth_key)作為加密金鑰。務必確保:

  1. Discuz 配置檔 config.inc.php 中的金鑰。
  2. 引入的 misc.func.php 中 authcode() 使用的金鑰。
  3. 您自行複製的 authcode() 函數(若未直接引入)使用的金鑰。

三者完全一致,否則 Cookie 無法被論壇識別。

整合建議

  • 直接引入法:若您的系統架構允許,直接 require_once 論壇的 common.inc.php,即可直接使用 $discuz_uid、$discuz_user 等全域變數,最簡潔可靠。
  • 獨立函數法:若有獨立公共函數庫,僅提取 authcode()、dsetcookie()、clearcookies() 三個函數至您的 func.php,並確保金鑰一致。
  • 安全提示:生產環境請務必啟用 HTTPS 傳輸登入表單,防止密碼明文傳輸被竊聽。

常見問題排查

現象可能原因解決方案
登入後論壇仍顯示未登入Cookie 域/路徑不匹配、加密金鑰不一致檢查 dsetcookie() 參數、統一 authcode 金鑰
提示「您輸入的用戶名或密碼錯誤」密碼加密方式不一致(如雙重 MD5)、字元集導致雜湊值不同確認雙方均為單次 md5($password),檢查資料庫連線字元集
安全碼/防灌水限制觸發同 IP 短時間多次失敗調整 $seccodedata['loginfailedcount'] 設定或清空 failedlogins 表

掌握上述核心機制,您即可在任何 PHP 系統中實現與 Discuz 的無縫同步登入,避免維護兩套用戶表帶來的管理負擔與資源浪費。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved