「想要達到像oracle 19c pdb連線管制的效果 使用者可以獨立連線到 adbbdb,但一旦連線到其中一個資料庫(例如 adb),就不能在同一個 psql session 中使用 \c 命令切換到另一個資料庫 (bdb)。」這個條件,在 PostgreSQL 的原生權限系統設計下,是辦不到的。讓我來解釋一下原因。

為什麼 PostgreSQL 原生設計辦不到?

這是因為 \c 命令的本質:

  • \c 是一個「重新連線」命令,而不是「資料庫內切換」命令。

    當您在 psql 中輸入 \c another_db 時,psql 客戶端會做以下事情:

    1. 斷開 當前與 adb 的連線。
    2. 嘗試建立一個全新的連線another_db
  • 每次新連線都會獨立進行權限檢查。

    PostgreSQL 伺服器在接收到新的連線請求時,它會檢查:

    1. 請求連線的 使用者 (Role)
    2. 請求連線的 資料庫 (Database)
    3. 該使用者是否對該資料庫擁有 CONNECT 權限
  • 只要使用者擁有目標資料庫的 CONNECT 權限,新的連線就能成功。

    如果您設定 user_a 可以連線到 adb 也 可以連線到 bdb,這代表 user_a 對 adb 和 bdb 都擁有 CONNECT 權限。那麼,當 user_a 在 adb 中執行 \c bdb 時,新的連線嘗試將會成功,因為 user_a 確實擁有連線到 bdb 的權限。


解決方案的限制與替代思考

由於 \c 命令的工作方式,您無法在使用者擁有兩個資料庫連線權限的同時,阻止他在 psql session 中使用 \c 進行切換。這不是 PostgreSQL 的權限不足,而是其設計使然。

如果這個需求是 絕對不能妥協 的,您可能需要考慮以下替代方案,但它們都會增加複雜性:

  1. 應用程式層面的控制 (最推薦且實用的方式):

    這是最常見且有效的解決方式。應用程式管理連線,而不是讓終端使用者直接操作 psql。

    • 每個連線池對應一個資料庫: 您的應用程式為 adb 維護一個連線池,為 bdb 維護另一個連線池。當使用者需要存取 adb 時,應用程式從 adb 的連線池中獲取連線;需要存取 bdb 時,從 bdb 的連線池中獲取。
    • 使用者無權直接操作 \c 應用程式使用者通常不會直接操作 psql,因此 \c 命令的存在就不是問題。即使他們有 psql 存取權限,您也可以給他們不同的使用者帳號,每個帳號只能連線到一個資料庫。
    • 管理者的 psql 存取: 只有需要多資料庫操作的管理者(例如您的工程師)才被授予可以直接使用 psql 並允許 \c 切換的超級用戶或特殊權限用戶。
  2. 為每個資料庫創建不同的使用者帳號 (如果您堅持 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 沒有 bdbCONNECT 權限而失敗。
    • 缺點: 這表示同一個「人」在不同資料庫時需要使用不同的使用者名稱/密碼,這增加了管理複雜性,也可能與您「user name一樣」的條件衝突。
  3. 自訂一個「更安全」的客戶端 (高度複雜,不推薦):

    理論上,您可以編寫一個自訂的 PostgreSQL 客戶端工具(而不是使用 psql),這個工具可以在其內部邏輯中限制 \c 或類似命令的行為。但這是一個非常複雜且通常不切實際的方案。


總結

基於 PostgreSQL 的原生設計和 \c 命令的行為,您無法在同一個 psql session 中允許用戶連線到多個資料庫,同時又禁止他們使用 \c 命令在這些資料庫之間進行切換

最實用且推薦的做法是:

  • 透過應用程式來管理資料庫連線。 讓應用程式負責根據用戶的需求連接到不同的資料庫,並限制用戶直接存取 psql 或提供特定權限的用戶給他們。
  • 明確理解 psql \c 的工作原理。 它是建立新連線,權限檢查始終會發生。

因此,您需要重新評估這個「連入adb之後不可以\c切換至bdb」的條件,看它是否可以在應用程式層面或其他方面得到滿足。

postgreSQL