文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  代理使用者

8.2.19 代理使用者

MySQL 伺服器使用驗證外掛程式驗證用戶端連線。驗證給定連線的外掛程式可以要求將連線 (外部) 使用者視為不同的使用者,以進行權限檢查。這使外部使用者能夠成為第二個使用者的代理;也就是說,承擔第二個使用者的權限

  • 外部使用者是代理使用者(可以偽裝或成為另一個使用者為人所知的使用者)。

  • 第二個使用者是被代理的使用者(其身分和權限可以由代理使用者承擔的使用者)。

本節說明代理使用者功能如何運作。如需關於驗證外掛程式的一般資訊,請參閱第 8.2.17 節,「可插拔驗證」。如需關於特定外掛程式的資訊,請參閱第 8.4.1 節,「驗證外掛程式」。如需關於撰寫支援代理使用者的驗證外掛程式的資訊,請參閱在驗證外掛程式中實作代理使用者支援

注意

代理可以獲得的一個管理優勢是,DBA 可以設定具有一組權限的單一帳戶,然後啟用多個代理使用者來擁有這些權限,而無需將權限個別指派給每個使用者。作為代理使用者的替代方案,DBA 可能會發現角色提供了一種將使用者對應到特定命名權限集的合適方法。可以將給定的單一角色授予每個使用者,以便實際上被授予適當的權限集。請參閱第 8.2.10 節,「使用角色」

代理使用者支援的需求

若要讓給定的驗證外掛程式發生代理,必須滿足以下條件

  • 必須支援代理,無論是外掛程式本身,還是由 MySQL 伺服器代表外掛程式。在後一種情況下,可能需要明確啟用伺服器支援;請參閱伺服器對代理使用者對應的支援

  • 必須設定外部代理使用者的帳戶,以便由外掛程式驗證。使用CREATE USER陳述式將帳戶與驗證外掛程式建立關聯,或使用ALTER USER來變更其外掛程式。

  • 被代理使用者的帳戶必須存在,並且被授予代理使用者要承擔的權限。為此,請使用CREATE USERGRANT陳述式。

  • 通常,會設定被代理的使用者,使其只能在代理情境中使用,而不能用於直接登入。

  • 代理使用者帳戶必須具有被代理帳戶的PROXY權限。為此,請使用GRANT陳述式。

  • 對於連線到代理帳戶以被視為代理使用者的用戶端,驗證外掛程式必須傳回與用戶端使用者名稱不同的使用者名稱,以指出被代理帳戶的使用者名稱,該使用者名稱定義代理使用者要承擔的權限。

    或者,對於伺服器提供代理映射的外掛程式,被代理的使用者是根據代理使用者所持有的 PROXY 權限來決定的。

代理機制僅允許將外部用戶端使用者名稱映射到被代理的使用者名稱。沒有提供映射主機名稱的功能。

  • 當用戶端連線到伺服器時,伺服器會根據用戶端程式傳遞的使用者名稱以及用戶端連線的主機來判斷適當的帳戶。

  • 如果該帳戶是代理帳戶,伺服器會嘗試透過使用驗證外掛程式傳回的使用者名稱和代理帳戶的主機名稱來尋找匹配的被代理帳戶,以判斷適當的被代理帳戶。被代理帳戶中的主機名稱將被忽略。

簡單的代理使用者範例

考慮以下帳戶定義

-- create proxy account
CREATE USER 'employee_ext'@'localhost'
  IDENTIFIED WITH my_auth_plugin
  AS 'my_auth_string';

-- create proxied account and grant its privileges;
-- use mysql_no_login plugin to prevent direct login
CREATE USER 'employee'@'localhost'
  IDENTIFIED WITH mysql_no_login;
GRANT ALL
  ON employees.*
  TO 'employee'@'localhost';

-- grant to proxy account the
-- PROXY privilege for proxied account
GRANT PROXY
  ON 'employee'@'localhost'
  TO 'employee_ext'@'localhost';

當用戶端以 employee_ext 從本機主機連線時,MySQL 會使用名為 my_auth_plugin 的外掛程式來執行驗證。假設 my_auth_plugin 根據 'my_auth_string' 的內容,或許還會查詢某些外部驗證系統,向伺服器傳回使用者名稱 employeeemployee 這個名稱與 employee_ext 不同,因此傳回 employee 表示要求伺服器為了權限檢查的目的,將外部使用者 employee_ext 視為本機使用者 employee

在這種情況下,employee_ext 是代理使用者,而 employee 是被代理的使用者。

伺服器會檢查 employee_ext (代理使用者) 是否擁有針對 employee (被代理的使用者) 的 PROXY 權限,來驗證是否可以為 employee 進行 employee_ext 的代理驗證。如果未授予此權限,則會發生錯誤。否則,employee_ext 將會假設 employee 的權限。伺服器會根據授予 employee 的權限來檢查 employee_ext 在用戶端工作階段期間執行的語句。在這種情況下,employee_ext 可以存取 employees 資料庫中的表格。

被代理的帳戶 employee 使用 mysql_no_login 驗證外掛程式來防止用戶端直接使用該帳戶登入。(假設已安裝此外掛程式。如需說明,請參閱章節 8.4.1.9,「不可登入的可插拔驗證」。) 有關保護被代理帳戶免受直接使用的其他方法,請參閱防止直接登入被代理的帳戶

發生代理時,可以使用 USER()CURRENT_USER() 函式來查看連線使用者(代理使用者)和在目前工作階段期間套用其權限的帳戶(被代理的使用者)之間的差異。對於剛才描述的範例,這些函式會傳回以下值

mysql> SELECT USER(), CURRENT_USER();
+------------------------+--------------------+
| USER()                 | CURRENT_USER()     |
+------------------------+--------------------+
| employee_ext@localhost | employee@localhost |
+------------------------+--------------------+

在建立代理使用者帳戶的 CREATE USER 語句中,指定支援代理的驗證外掛程式的 IDENTIFIED WITH 子句後面可以選擇性地接一個 AS 'auth_string' 子句,指定當使用者連線時伺服器傳遞給外掛程式的字串。如果存在,該字串會提供資訊,以協助外掛程式判斷如何將代理(外部)用戶端使用者名稱映射到被代理的使用者名稱。是否需要 AS 子句取決於每個外掛程式。如果需要,驗證字串的格式取決於外掛程式打算如何使用它。有關其接受的驗證字串值的資訊,請參閱指定外掛程式的文件。

防止直接登入被代理的帳戶

一般而言,被代理的帳戶僅供透過代理帳戶使用。也就是說,用戶端使用代理帳戶連線,然後映射到適當的被代理使用者並假設其權限。

有多種方法可以確保被代理的帳戶不能直接使用

  • 將帳戶與 mysql_no_login 驗證外掛程式相關聯。在這種情況下,無論如何都無法使用該帳戶進行直接登入。這假設已安裝此外掛程式。如需說明,請參閱章節 8.4.1.9,「不可登入的可插拔驗證」

  • 在建立帳戶時包含 ACCOUNT LOCK 選項。請參閱章節 15.7.1.3,「CREATE USER 語句」。使用此方法時,也請包含密碼,以便稍後解除鎖定該帳戶時,不會在沒有密碼的情況下被存取。(如果啟用 validate_password 元件,即使帳戶已鎖定,也不允許建立沒有密碼的帳戶。請參閱章節 8.4.3,「密碼驗證元件」。)

  • 建立一個帶有密碼的帳戶,但不要告訴任何人該密碼。如果您不讓任何人知道該帳戶的密碼,則用戶端無法使用它直接連線到 MySQL 伺服器。

授予和撤銷 PROXY 權限

需要 PROXY 權限,才能讓外部使用者以另一個使用者的身分連線並擁有其權限。若要授予此權限,請使用 GRANT 語句。例如

GRANT PROXY ON 'proxied_user' TO 'proxy_user';

此語句會在 mysql.proxies_priv 授權表中建立一列。

在連線時,proxy_user 必須表示有效的外部驗證 MySQL 使用者,而 proxied_user 必須表示有效的本機驗證使用者。否則,連線嘗試會失敗。

對應的 REVOKE 語法為

REVOKE PROXY ON 'proxied_user' FROM 'proxy_user';

MySQL GRANTREVOKE 語法擴充功能會像往常一樣運作。範例

-- grant PROXY to multiple accounts
GRANT PROXY ON 'a' TO 'b', 'c', 'd';

-- revoke PROXY from multiple accounts
REVOKE PROXY ON 'a' FROM 'b', 'c', 'd';

-- grant PROXY to an account and enable the account to grant
-- PROXY to the proxied account
GRANT PROXY ON 'a' TO 'd' WITH GRANT OPTION;

-- grant PROXY to default proxy account
GRANT PROXY ON 'a' TO ''@'';

在以下情況下可以授予 PROXY 權限

  • 由具有 proxied_userGRANT PROXY ... WITH GRANT OPTION 的使用者授予。

  • proxied_user 為自己授予:USER() 的值必須與 CURRENT_USER()proxied_user 完全匹配,包括帳戶名稱的使用者名稱和主機名稱部分。

在 MySQL 安裝期間建立的初始 root 帳戶具有 ''@''PROXY ... WITH GRANT OPTION 權限,也就是說,適用於所有使用者和所有主機。這讓 root 可以設定代理使用者,並將設定代理使用者的權限委派給其他帳戶。例如,root 可以執行此操作

CREATE USER 'admin'@'localhost'
  IDENTIFIED BY 'admin_password';
GRANT PROXY
  ON ''@''
  TO 'admin'@'localhost'
  WITH GRANT OPTION;

這些語句會建立一個可以管理所有 GRANT PROXY 映射的 admin 使用者。例如,admin 可以執行此操作

GRANT PROXY ON sally TO joe;

預設代理使用者

若要指定某些或所有使用者應使用給定的驗證外掛程式連線,請建立一個具有空使用者名稱和主機名稱 (''@'') 的 空白 MySQL 帳戶,將其與該外掛程式相關聯,並讓外掛程式傳回真實的已驗證使用者名稱(如果與空白使用者不同)。假設存在一個名為 ldap_auth 的外掛程式,該外掛程式實作 LDAP 驗證並將連線使用者映射到開發人員或管理員帳戶。若要設定使用者對這些帳戶的代理,請使用以下語句

-- create default proxy account
CREATE USER ''@''
  IDENTIFIED WITH ldap_auth
  AS 'O=Oracle, OU=MySQL';

-- create proxied accounts; use
-- mysql_no_login plugin to prevent direct login
CREATE USER 'developer'@'localhost'
  IDENTIFIED WITH mysql_no_login;
CREATE USER 'manager'@'localhost'
  IDENTIFIED WITH mysql_no_login;

-- grant to default proxy account the
-- PROXY privilege for proxied accounts
GRANT PROXY
  ON 'manager'@'localhost'
  TO ''@'';
GRANT PROXY
  ON 'developer'@'localhost'
  TO ''@'';

現在假設用戶端以如下方式連線

$> mysql --user=myuser --password ...
Enter password: myuser_password

伺服器找不到定義為 MySQL 使用者的 myuser,但由於存在與用戶端使用者名稱和主機名稱匹配的空白使用者帳戶 (''@''),因此伺服器會針對該帳戶驗證用戶端。伺服器會呼叫 ldap_auth 驗證外掛程式,並將 myusermyuser_password 作為使用者名稱和密碼傳遞給它。

如果 ldap_auth 外掛程式在 LDAP 目錄中找不到 myuser_passwordmyuser 的正確密碼,驗證會失敗,伺服器會拒絕連線。

如果密碼正確,並且 ldap_auth 發現 myuser 是開發人員,它會將使用者名稱 developer 而不是 myuser 傳回 MySQL 伺服器。傳回與用戶端使用者名稱 myuser 不同的使用者名稱,表示應將 myuser 視為代理。伺服器會驗證 ''@'' 是否可以驗證為 developer (因為 ''@'' 擁有 PROXY 權限可以這樣做),並接受連線。工作階段會繼續,myuser 擁有被代理使用者 developer 的權限。(這些權限應該由 DBA 使用 GRANT 語句設定,此處未顯示。) USER()CURRENT_USER() 函式會傳回以下值

mysql> SELECT USER(), CURRENT_USER();
+------------------+---------------------+
| USER()           | CURRENT_USER()      |
+------------------+---------------------+
| myuser@localhost | developer@localhost |
+------------------+---------------------+

如果外掛程式反而發現 myuser 是管理員,則會傳回 manager 作為使用者名稱,並且工作階段會繼續,myuser 擁有被代理使用者 manager 的權限。

mysql> SELECT USER(), CURRENT_USER();
+------------------+-------------------+
| USER()           | CURRENT_USER()    |
+------------------+-------------------+
| myuser@localhost | manager@localhost |
+------------------+-------------------+

為求簡單,外部驗證不能是多層級的:在前面的範例中,不會考慮 developermanager 的認證。但是,如果用戶端嘗試直接以 developermanager 帳戶連線和驗證,則仍然會使用它們,這就是為什麼應保護這些被代理的帳戶免受直接登入 (請參閱防止直接登入被代理的帳戶)。

預設代理使用者和匿名使用者衝突

如果您打算建立預設代理使用者,請檢查是否有其他現有的 符合任何使用者帳戶優先於預設代理使用者,因為它們可能會阻止該使用者如預期般運作。

在前面的討論中,預設代理使用者帳戶在主機部分具有 '',這與任何主機都匹配。如果您設定了預設代理使用者,請務必同時檢查是否存在具有相同使用者部分且在主機部分具有 '%' 的非代理帳戶,因為 '%' 也與任何主機匹配,但根據伺服器在內部對帳戶列進行排序的規則,它的優先順序高於 '' (請參閱章節 8.2.6,「存取控制,階段 1:連線驗證」)。

假設 MySQL 安裝包含這兩個帳戶

-- create default proxy account
CREATE USER ''@''
  IDENTIFIED WITH some_plugin
  AS 'some_auth_string';
-- create anonymous account
CREATE USER ''@'%'
  IDENTIFIED BY 'anon_user_password';

第一個帳戶(''@'')旨在作為預設的代理使用者,用於驗證不符合任何更具體帳戶的使用者連線。第二個帳戶(''@'%')是一個匿名使用者帳戶,建立此帳戶可能是為了讓沒有自己帳戶的使用者能夠匿名連線。

這兩個帳戶都具有相同的使用者部分(''),可匹配任何使用者。而且,每個帳戶都具有可匹配任何主機的主機部分。儘管如此,在連線嘗試的帳戶匹配中,存在優先順序,因為匹配規則會將 '%' 的主機排在 '' 之前。對於不符合任何更具體帳戶的帳戶,伺服器會嘗試針對 ''@'%'(匿名使用者)而非 ''@''(預設代理使用者)來驗證它們。因此,永遠不會使用預設的代理帳戶。

為了避免這個問題,請使用以下其中一種策略

  • 移除匿名帳戶,使其不會與預設的代理使用者衝突。

  • 使用比匿名使用者更早匹配的、更具體的預設代理使用者。例如,若要僅允許 localhost 代理連線,請使用 ''@'localhost'

    CREATE USER ''@'localhost'
      IDENTIFIED WITH some_plugin
      AS 'some_auth_string';

    此外,修改所有 GRANT PROXY 陳述式,以將 ''@'localhost' 而非 ''@'' 指定為代理使用者。

    請注意,此策略會阻止來自 localhost 的匿名使用者連線。

  • 使用具名的預設帳戶,而不是匿名的預設帳戶。如需此技巧的範例,請參閱使用 authentication_windows 外掛程式的說明。請參閱 第 8.4.1.6 節:「Windows 可插拔驗證」

  • 建立多個代理使用者,一個用於本機連線,另一個用於其他所有(遠端連線)。當本機使用者應與遠端使用者擁有不同的權限時,這特別有用。

    建立代理使用者

    -- create proxy user for local connections
    CREATE USER ''@'localhost'
      IDENTIFIED WITH some_plugin
      AS 'some_auth_string';
    -- create proxy user for remote connections
    CREATE USER ''@'%'
      IDENTIFIED WITH some_plugin
      AS 'some_auth_string';

    建立被代理的使用者

    -- create proxied user for local connections
    CREATE USER 'developer'@'localhost'
      IDENTIFIED WITH mysql_no_login;
    -- create proxied user for remote connections
    CREATE USER 'developer'@'%'
      IDENTIFIED WITH mysql_no_login;

    將對應的被代理帳戶的 PROXY 權限授予每個代理帳戶

    GRANT PROXY
      ON 'developer'@'localhost'
      TO ''@'localhost';
    GRANT PROXY
      ON 'developer'@'%'
      TO ''@'%';

    最後,將適當的權限授予本機和遠端的被代理使用者(未顯示)。

    假設 some_plugin/'some_auth_string' 的組合會導致 some_plugin 將用戶端使用者名稱對應到 developer。本機連線會符合 ''@'localhost' 代理使用者,該使用者會對應到 'developer'@'localhost' 被代理的使用者。遠端連線會符合 ''@'%' 代理使用者,該使用者會對應到 'developer'@'%' 被代理的使用者。

伺服器對代理使用者對應的支援

某些驗證外掛程式會自行實作代理使用者對應(例如,PAM 和 Windows 驗證外掛程式)。其他驗證外掛程式預設不支援代理使用者。在這些外掛程式中,有些可以請求 MySQL 伺服器本身根據授予的代理權限對應代理使用者:mysql_native_password(已棄用)、sha256_password(已棄用)。如果啟用 check_proxy_users 系統變數,伺服器會針對任何提出此要求的驗證外掛程式執行代理使用者對應

  • 依預設,check_proxy_users 已停用,因此即使驗證外掛程式要求伺服器支援代理使用者,伺服器也不會執行任何代理使用者對應。

  • 如果啟用 check_proxy_users,也可能需要啟用外掛程式專用的系統變數,才能利用伺服器代理使用者對應支援

例如,若要啟用以上所有功能,請在 my.cnf 檔案中使用下列幾行來啟動伺服器

[mysqld]
check_proxy_users=ON
mysql_native_password_proxy_users=ON
sha256_password_proxy_users=ON

假設已啟用相關的系統變數,請照常使用 CREATE USER 建立代理使用者,然後將 PROXY 權限授予要視為被代理使用者的單一其他帳戶。當伺服器收到針對代理使用者的成功連線要求時,它會發現該使用者具有 PROXY 權限,並使用此權限來判斷適當的被代理使用者。

-- create proxy account
CREATE USER 'proxy_user'@'localhost'
  IDENTIFIED WITH mysql_native_password
  BY 'password';

-- create proxied account and grant its privileges;
-- use mysql_no_login plugin to prevent direct login
CREATE USER 'proxied_user'@'localhost'
  IDENTIFIED WITH mysql_no_login;
-- grant privileges to proxied account
GRANT ...
  ON ...
  TO 'proxied_user'@'localhost';

-- grant to proxy account the
-- PROXY privilege for proxied account
GRANT PROXY
  ON 'proxied_user'@'localhost'
  TO 'proxy_user'@'localhost';

若要使用代理帳戶,請使用其名稱和密碼連線到伺服器

$> mysql -u proxy_user -p
Enter password: (enter proxy_user password here)

驗證成功後,伺服器會發現 proxy_user 具有 proxied_userPROXY 權限,並且工作階段會以 proxy_user 擁有 proxied_user 的權限繼續進行。

伺服器執行的代理使用者對應受到以下限制

  • 伺服器不會代理到匿名使用者或從匿名使用者代理,即使已授予相關的 PROXY 權限也是如此。

  • 當單一帳戶已獲授多個被代理帳戶的代理權限時,伺服器代理使用者對應是不確定的。因此,不建議將多個被代理帳戶的代理權限授予單一帳戶。

代理使用者系統變數

兩個系統變數有助於追蹤代理登入程序

  • proxy_user:如果未使用代理,則此值為 NULL。否則,它會指示代理使用者帳戶。例如,如果用戶端通過 ''@'' 代理帳戶進行驗證,則此變數會設定如下

    mysql> SELECT @@proxy_user;
    +--------------+
    | @@proxy_user |
    +--------------+
    | ''@''        |
    +--------------+
  • external_user:有時,驗證外掛程式可能會使用外部使用者來驗證 MySQL 伺服器。例如,當使用 Windows 原生驗證時,使用 Windows API 進行驗證的外掛程式不需要傳遞給它的登入 ID。但是,它仍然使用 Windows 使用者 ID 來進行驗證。外掛程式可能會使用 external_user 唯讀工作階段變數,將此外部使用者 ID(或其前 512 個 UTF-8 位元組)傳回伺服器。如果外掛程式未設定此變數,則其值為 NULL