「想要達到像oracle 19c pdb連線管制的效果 使用者可以獨立連線到 adb 和 bdb,但一旦連線到其中一個資料庫(例如 adb),就不能在同一個 psql session 中使用 \c 命令切換到另一個資料庫 (bdb)。」這個條件,在 PostgreSQL 的原生權限系統設計下,是辦不到的。讓我來解釋一下原因。
為什麼 PostgreSQL 原生設計辦不到?
這是因為 \c 命令的本質:
-
\c 是一個「重新連線」命令,而不是「資料庫內切換」命令。
當您在 psql 中輸入 \c another_db 時,psql 客戶端會做以下事情:
- 斷開 當前與
adb的連線。 - 嘗試建立一個全新的連線 到
another_db。
- 斷開 當前與
-
每次新連線都會獨立進行權限檢查。
PostgreSQL 伺服器在接收到新的連線請求時,它會檢查:
- 請求連線的 使用者 (Role)。
- 請求連線的 資料庫 (Database)。
- 該使用者是否對該資料庫擁有
CONNECT權限。
-
只要使用者擁有目標資料庫的 CONNECT 權限,新的連線就能成功。
如果您設定 user_a 可以連線到 adb 也 可以連線到 bdb,這代表 user_a 對 adb 和 bdb 都擁有 CONNECT 權限。那麼,當 user_a 在 adb 中執行 \c bdb 時,新的連線嘗試將會成功,因為 user_a 確實擁有連線到 bdb 的權限。
解決方案的限制與替代思考
由於 \c 命令的工作方式,您無法在使用者擁有兩個資料庫連線權限的同時,阻止他在 psql session 中使用 \c 進行切換。這不是 PostgreSQL 的權限不足,而是其設計使然。
如果這個需求是 絕對不能妥協 的,您可能需要考慮以下替代方案,但它們都會增加複雜性:
-
應用程式層面的控制 (最推薦且實用的方式):
這是最常見且有效的解決方式。應用程式管理連線,而不是讓終端使用者直接操作 psql。
- 每個連線池對應一個資料庫: 您的應用程式為
adb維護一個連線池,為bdb維護另一個連線池。當使用者需要存取adb時,應用程式從adb的連線池中獲取連線;需要存取bdb時,從bdb的連線池中獲取。 - 使用者無權直接操作
\c: 應用程式使用者通常不會直接操作psql,因此\c命令的存在就不是問題。即使他們有psql存取權限,您也可以給他們不同的使用者帳號,每個帳號只能連線到一個資料庫。 - 管理者的
psql存取: 只有需要多資料庫操作的管理者(例如您的工程師)才被授予可以直接使用psql並允許\c切換的超級用戶或特殊權限用戶。
- 每個連線池對應一個資料庫: 您的應用程式為
-
為每個資料庫創建不同的使用者帳號 (如果您堅持 psql 命令行操作):
如果您堅持使用者需要透過 psql 操作,但又想「物理性」地阻止切換,唯一的方法就是讓使用者每次連線時都使用不同的使用者帳號,並且每個帳號只授予單一資料庫的 CONNECT 權限。
- Example:
user_a_for_adb只能連線adb。user_a_for_bdb只能連線bdb。
- 這樣,當
psql -U user_a_for_adb -d adb連線後,如果執行\c bdb,會因為user_a_for_adb沒有bdb的CONNECT權限而失敗。 - 缺點: 這表示同一個「人」在不同資料庫時需要使用不同的使用者名稱/密碼,這增加了管理複雜性,也可能與您「user name一樣」的條件衝突。
- Example:
-
自訂一個「更安全」的客戶端 (高度複雜,不推薦):
理論上,您可以編寫一個自訂的 PostgreSQL 客戶端工具(而不是使用 psql),這個工具可以在其內部邏輯中限制 \c 或類似命令的行為。但這是一個非常複雜且通常不切實際的方案。
總結
基於 PostgreSQL 的原生設計和 \c 命令的行為,您無法在同一個 psql session 中允許用戶連線到多個資料庫,同時又禁止他們使用 \c 命令在這些資料庫之間進行切換。
最實用且推薦的做法是:
- 透過應用程式來管理資料庫連線。 讓應用程式負責根據用戶的需求連接到不同的資料庫,並限制用戶直接存取
psql或提供特定權限的用戶給他們。 - 明確理解
psql \c的工作原理。 它是建立新連線,權限檢查始終會發生。
因此,您需要重新評估這個「連入adb之後不可以\c切換至bdb」的條件,看它是否可以在應用程式層面或其他方面得到滿足。