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

Laravel 實作 SSO 單點登入完整方案(跨子域名驗證)

     編輯:PHP 相關知識

Laravel 實作 SSO 單點登入完整方案

單點登入 (SSO) 讓使用者在多個子系統(子域名)間僅需登入一次。本文以 Laravel 為例,實作「中央認證站 (a.example.com) + 子系統 (b.example.com, c.example.com)」架構,採用 Ticket + Cache 驗證機制。

架構角色定義

  • a.example.com:身分驗證中心(IdP),負責帳密驗證、發放 Ticket、Session 管理。
  • b.example.com / c.example.com:服務提供者 (SP),攜帶導向參數導向 IdP 登入,登入成功後接收 Ticket 向 IdP 驗證並建立本地 Session。

IdP 端:登入與 Ticket 發放

<?php
// AuthController@login
public function login(Request $request) {
    $credentials = $request->only('email', 'password');
    if (Auth::attempt($credentials)) {
        $user = Auth::user();
        $ticket = $this->generateTicket($user);
        $redirectUrl = $request->input('source') . '?ticket=' . $ticket;
        return redirect($redirectUrl);
    }
    return back()->withErrors(['登入失敗']);
}

private function generateTicket($user) {
    $ticket = md5(time() . config('app.key') . $user->id);
    // 快取 2 分鐘,值為使用者資料陣列
    Cache::put($ticket, ['uid' => $user->id, 'name' => $user->name], 120);
    return $ticket;
}
?>

IdP 端:Ticket 驗證 API

<?php
// AuthController@checkTicket
public function checkTicket(Request $request) {
    $ticket = $request->input('ticket');
    $data = Cache::get($ticket);
    if ($data) {
        // 驗證成功後刪除 Ticket 防重放
        Cache::forget($ticket);
        return response()->json(['state' => 'SUCCESS', 'result' => $data]);
    }
    return response()->json(['state' => 'FAIL', 'msg' => 'Ticket 無效或已過期']);
}
?>

SP 端:全域中介層攔截 Ticket

<?php
// app/Http/Middleware/CasAuthenticate.php
public function handle($request, Closure $next) {
    $ticket = $request->input('ticket');
    if ($ticket) {
        $response = Http::get('https://a.example.com/auth/check-ticket', ['ticket' => $ticket]);
        $result = $response->json();
        if ($result['state'] === 'SUCCESS') {
            // 登入本地使用者(需同步使用者資料或共用 users 表)
            Auth::loginUsingId($result['result']['uid']);
            // 移除 ticket 參數避免殘留
            return redirect($request->url());
        }
    }
    return $next($request);
}
?>

於 app/Http/Kernel.php 註冊中介層:

protected $middlewareGroups = [
    'web' => [
        // ...
        \App\Http\Middleware\CasAuthenticate::class,
    ],
];

跨子域名 Session 共享設定

於 config/session.php 設定:

'domain' => '.example.com', // 所有子域名共享 Session Cookie
'same_site' => 'lax',       // 允許跨站請求攜帶 Cookie

流程時序圖

  1. 用戶訪問 b.example.com → 未登入 → 導向 a.example.com/login?source=https://b.example.com/dashboard
  2. 用戶於 a.example.com 輸入帳密 → 驗證成功 → 生成 Ticket 存入 Cache → 導向 https://b.example.com/dashboard?ticket=xxx
  3. b.example.com 中介層攔截 Ticket → 呼叫 a.example.com/auth/check-ticket → 驗證成功 → 本地登入用戶 → 重導至原頁面

已知限制與改進方向

  • Ticket 單次使用:驗證後即刪除,防止重放攻擊。
  • Cache 過期與 Session 不同步:若 IdP Cache 過期但 SP Session 仍有效,跨系統跳轉可能需重新登入。改進:引入 Refresh Token 機制或共用 Redis Session。
  • 用戶資料同步:各系統需同步用戶表或透過 API 即時取得用戶資料。

延伸閱讀

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