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

PHP 整合 Discuz! 單點登入(SSO)完整實作指南

     編輯:PHP 相關知識

前言

Discuz! 作為經典 PHP 論壇系統,其 UCenter 機制提供了跨應用的單點登入(SSO)能力。本文詳細說明 UCenter 通訊原理、配置要點、API 調用流程、同步登入/登出實作、常見坑點與現代化替代方案,助你快速將既有 PHP 系統與 Discuz! 整合。

UCenter 架構與通訊原理

  • UCenter Server:獨立部署的用戶中心,提供用戶管理、通訊 API(uc.php)。
  • Application (Client):Discuz! 本體、你的 PHP 系統、其他子系統,各有唯一 UC_APPID。
  • 通訊方式:
    • UC_CONNECT=mysql:直接讀寫 UCenter 資料庫(高效能、需同網段、資料庫帳號權限)。
    • UC_CONNECT= (空):**API 模式**,透過 HTTP 請求 UC_API/uc.php(跨網段、安全、標準)。
  • 同步機制:應用登入/登出時,調用 UCenter API 取得同步代碼(JS 片段),輸出到瀏覽器執行,觸發其他應用的 uc.php 完成 Session/Cookie 同步。

配置檔案設定

1. UCenter 端:新增應用

登入 UCenter 管理後台 → 應用管理 → 新增應用:

  • 應用類型:其它(或自定義)
  • 應用名稱:你的系統名稱
  • 應用 URL:https://your-app.com
  • 通訊金鑰 UC_KEY:必須與客戶端配置完全一致
  • IP:留空或填寫客戶端伺服器 IP
  • 啟用同步登入、同步登出

2. 客戶端配置 config.inc.php(或 uc_client/config.inc.php)

<?php
// UCenter 客戶端配置
define('UC_CONNECT', 'mysql'); // 或 '' 使用 API 模式
define('UC_DBHOST', 'localhost');
define('UC_DBUSER', 'ucenter_user');
define('UC_DBPW', 'secure_password');
define('UC_DBNAME', 'ucenter');
define('UC_DBCHARSET', 'utf8mb4');
define('UC_DBTABLEPRE', 'ucenter.uc_');
define('UC_KEY', 'your_very_long_random_key_here'); // 必須與 UCenter 後台一致
define('UC_API', 'https://ucenter.yourdomain.com'); // UCenter 入口 URL
define('UC_CHARSET', 'utf-8');
define('UC_IP', ''); // API 模式下若域名解析有問題可填 IP
define('UC_APPID', 3); // UCenter 後台分配的應用 ID
define('UC_PPP', 20); // 每頁數量

// Cookie 設定(跨域同步需注意 domain 設定)
$_UC = [];
$_UC['cookiedomain'] = '.yourdomain.com'; // 共用根域名才能跨子域同步 Cookie
$_UC['cookiepath'] = '/';
$_UC['cookiepre'] = 'uc_';
$_UC['cookietime'] = 31536000; // 1 年

核心 API 調用流程

1. 引入 UCenter 客戶端庫

<?php
require_once __DIR__ . '/uc_client/client.php'; // 根據實際路徑調整

2. 用戶登入驗證並同步登入

<?php
// login.php
// 1. 驗證用戶名密碼(呼叫 UCenter 驗證)
list($uid, $username, $password, $email) = uc_user_login($_POST['username'], $_POST['password']);

if ($uid > 0) {
    // 登入成功
    // 2. 產生同步登入代碼(包含其他應用的 JS)
    $synlogin = uc_user_synlogin($uid);
    
    // 3. 建立本地 Session
    $_SESSION['uid'] = $uid;
    $_SESSION['username'] = $username;
    // ... 其他本地登入邏輯
    
    // 4. 輸出同步代碼(關鍵:必須輸出到瀏覽器執行!)
    echo $synlogin;
    
    // 5. 跳轉或回傳成功
    echo '<script>window.location.href="/dashboard";</script>';
    exit;
} elseif ($uid == -1) {
    echo '用戶不存在或被刪除';
} elseif ($uid == -2) {
    echo '密碼錯誤';
} else {
    echo '未知錯誤';
}

3. 用戶註冊同步

<?php
// register.php
$uid = uc_user_register($_POST['username'], $_POST['password'], $_POST['email']);

if ($uid > 0) {
    // 註冊成功,同步登入
    $synlogin = uc_user_synlogin($uid);
    echo $synlogin;
    echo '<script>alert("註冊成功"); window.location.href="/";</script>';
} elseif ($uid == -1) {
    echo '用戶名不合法';
} elseif ($uid == -2) {
    echo '包含敏感詞';
} elseif ($uid == -3) {
    echo '用戶名已存在';
} elseif ($uid == -4) {
    echo 'Email 格式錯誤';
} elseif ($uid == -5) {
    echo 'Email 不允許註冊';
} elseif ($uid == -6) {
    echo 'Email 已被註冊';
} else {
    echo '註冊失敗';
}

4. 同步登出

<?php
// logout.php
// 1. 取得同步登出代碼
$synlogout = uc_user_synlogout();

// 2. 銷毀本地 Session
session_destroy();
// 或
$_SESSION = [];
if (ini_get('session.use_cookies')) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
}

// 3. 輸出同步代碼
echo $synlogout;
echo '<script>window.location.href="/";</script>';

5. 其他常用同步 API

API 模式通訊細節(UC_CONNECT='')

若無法直連資料庫,需實作 api/uc.php 接收 UCenter 回調:

<?php
// api/uc.php
define('API_DELETEUSER', 1);
define('API_RENAMEUSER', 1);
define('API_GETTAG', 0);
define('API_SYNLOGIN', 1);   // 同步登入
define('API_SYNLOGOUT', 1);  // 同步登出
define('API_UPDATEPW', 1);   // 更新密碼
define('API_UPDATEBADWORDS', 0);
define('API_UPDATEHOSTS', 0);
define('API_UPDATEAPPS', 1);
define('API_UPDATECLIENT', 1);
define('API_UPDATECREDIT', 0);
define('API_GETCREDITSETTINGS', 0);
define('API_GETCREDIT', 0);
define('API_UPDATECREDITSETTINGS', 0);

require_once '../uc_client/client.php';

// uc.php 會自動處理 $_GET['code'] 解密、分派對應函式
// 你需要實作以下函式(在同目錄下建立 api/ 目錄):
// function synlogin($get, $post) { /* 建立本地 session/cookie */ }
// function synlogout($get, $post) { /* 銷毀本地 session/cookie */ }
// function updatepw($get, $post) { /* 更新本地密碼 */ }
// function deleteuser($get, $post) { /* 刪除本地用戶 */ }
// ... 參考 uc_client/model/base.php

跨域 Cookie 同步關鍵設定

若 UCenter 在 ucenter.example.com,應用在 app.example.com:

  1. $_UC['cookiedomain'] = '.example.com';(注意前綴點)
  2. 確保所有應用 session.cookie_domain = .example.com(php.ini 或 session_set_cookie_params())
  3. P3P 標頭(IE 兼容):header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
  4. SameSite 設定:session_set_cookie_params(['samesite' => 'Lax']) 或 None(需 Secure)

常見問題排查

現象可能原因解決
同步代碼輸出但不生效JS 錯誤、域名不匹配、Cookie 未送達F12 Console 看錯誤、檢查 Cookie Domain、Network 看請求是否發出
UC_KEY 不正確雙端金鑰不一致、編碼問題重新生成 32 字元隨機鍵,雙端同步更新
API 模式通訊失敗防火牆阻擋、DNS 解析、SSL 憑證驗證失敗允許出站 80/443、curl -v 測試、curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)(測試用)
登入後刷新掉線Session 儲存路徑權限、Session ID 重生成檢查 session.save_path 權限、避免每請求 session_regenerate_id()
同步登出無效未輸出 uc_user_synlogout() 返回的 JS確認 echo $synlogout; 在輸出

現代化替代方案:OAuth 2.0 / OpenID Connect

UCenter 屬於早期架構,新專案建議採用標準協定:

  • Keycloak / Authentik / Authelia:開源身分識別提供者,支援 OIDC、SAML、LDAP。
  • Laravel Passport / Sanctum:若主系統用 Laravel,可直接做 OAuth Server。
  • Discuz! X 官方支援 OAuth:新版已內建 OAuth Server 功能,可作為 IdP。
  • JWT 無狀態認證:微服務架構下避免 Session 同步複雜度。

遷移策略建議

  1. 保留 UCenter 相容層,新系統對接 OIDC。
  2. 建立用戶遷移腳本:UCenter → 新 IdP(密碼雜湊需相容或強制重設)。
  3. 逐步切換子系統,雙軌並行期間同步雙向寫入。
  4. 完全切換後下線 UCenter。

Discuz! UCenter 雖屬經典架構,但在既有生態整合中仍具實用價值。掌握其通訊流程、配置細節、同步機制,並建立向現代身分認證標準遷移的路線圖,才能在維護舊系統與建設新架構間取得平衡。

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