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

PHP 多域名單點登入 (SSO) 解決方案:Cookie 跨域共享與介面協定

     編輯:PHP 綜合知識

問題背景

企業常擁有多個子系統(如 app.a.com、shop.a.com、admin.a.com),期望用戶在任一系統登入後,其餘系統自動識別登入狀態,無需重複輸入帳密。這即為單點登入需求。

方案一:主域名 Cookie 共享(最簡單)

前提:所有系統共享同一主域名(如 *.a.com)。

// 登入成功後,設定 Cookie domain 為主域名
setcookie('auth_token', $encryptedToken, [
    'expires'  => time() + 86400 * 7,
    'path'     => '/',
    'domain'   => '.a.com',   // 關鍵:前綴點號表示所有子域
    'secure'   => true,       // 僅 HTTPS
    'httponly' => true,       // 防 XSS 竊取
    'samesite' => 'Lax',      // CSRF 保護
]);

// 各子系統驗證
$token = $_COOKIE['auth_token'] ?? '';
if ($token && $user = validateToken($token)) {
    // 自動登入
    $_SESSION['user_id'] = $user['id'];
}

優點:無需額外服務、實作極簡。
缺點:僅限同主域名;安全性依賴 Token 加密強度;無法支援完全不同域名(如 b.com)。

方案二:中心化認證服務 + 介面回呼(跨域名通用)

架構圖

用戶 → 子系統 A (未登入) → 重導向 → 登入中心 (sso.com)
                                    ↓ 登入成功
                            設定 sso.com Cookie
                                    ↓
                            回呼子系統 A 介面 /sso/callback?token=xxx
                                    ↓
                            子系統 A 驗證 Token、建立本地 Session
                                    ↓
                            用戶訪問子系統 B → 子系統 B 檢查本地 Session
                                無 → 請求登入中心驗證介面 → 有效則建立 Session

核心介面協定

介面方法說明
/sso/loginGET登入中心頁面,帶 redirect_url 參數
/sso/verifyPOST子系統攜帶 Token 請求驗證,回傳用戶資料 JSON
/sso/logoutPOST登出通知,子系統註冊回呼 URL,中心登出時批量通知

子系統實作範例

// 登入檢查中介層
function checkSsoLogin() {
    if (isset($_SESSION['user_id'])) return $_SESSION['user_id'];

    $token = $_GET['sso_token'] ?? $_COOKIE['sso_token'] ?? '';
    if (!$token) {
        // 重導向至登入中心
        $redirect = urlencode('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
        header("Location: https://sso.com/sso/login?redirect_url=$redirect");
        exit;
    }

    // 驗證 Token
    $user = verifyTokenWithSsoCenter($token);
    if (!$user) {
        // Token 無效,清除並重試
        setcookie('sso_token', '', time()-3600, '/', '.a.com');
        header('Location: ' . $_SERVER['REQUEST_URI']);
        exit;
    }

    $_SESSION['user_id'] = $user['id'];
    $_SESSION['user_data'] = $user;
    // 同步寫入本地 Cookie 供後續請求
    setcookie('sso_token', $token, time()+86400*7, '/', '.a.com', true, true);
    return $user['id'];
}

// 登入中心驗證介面
function verifyTokenWithSsoCenter($token) {
    $ch = curl_init('https://sso.com/sso/verify');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => ['token' => $token],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    return $res ? json_decode($res, true) : false;
}

登出同步機制

  1. 用戶在任一系統點擊登出
  2. 該系統呼叫登入中心 /sso/logout,攜帶系統識別碼
  3. 登入中心清除中心 Session/Cookie,並異步並行通知所有已註冊子系統的登出回呼 URL
  4. 各子系統收到通知,清除本地 Session/Cookie

方案三:JWT 無狀態 Token(微服務友善)

登入中心簽發 JWT(含 sub, exp, aud, roles 等),子系統僅需驗證簽名與過期時間,無需呼叫中心驗證介面,極大降低耦合與延遲。

// 登入中心簽發
$payload = ['sub' => $userId, 'exp' => time()+3600, 'roles' => $roles];
$jwt = JWT::encode($payload, $privateKey, 'RS256');

// 子系統驗證 (需公鑰)
try {
    $payload = JWT::decode($jwt, $publicKey, ['RS256']);
    // 可選:檢查 aud、權限
    $_SESSION['user_id'] = $payload->sub;
} catch (Exception $e) {
    // 無效
}

安全性強化清單

  • 全站強制 HTTPS,Cookie 設 Secure、HttpOnly
  • Token 簽名採用非對稱加密 (RS256/ES256),私鑰僅登入中心持有
  • 實作 Token 黑名單/版本號機制支援強制登出
  • 限制 Token 存活時間,配合 Refresh Token 機制
  • 登入中心實施速率限制、帳號鎖定、異常登入告警
  • 定期輪換簽名金鑰

總結與選型建議

場景推薦方案複雜度
同主域名多子系統方案一:主域名 Cookie低
不同域名、傳統單體應用方案二:中心化 SSO + 回呼中
微服務、多語言、高併發方案三:JWT 無狀態中高
企業級、需整合 LDAP/OAuth2Keycloak / Auth0 / Casdoor 等成熟 IDP低(集成)

無論選擇哪種方案,核心原則皆為:認證與業務解耦、Token 傳輸加密、最小權限、完整審計日誌。

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