MySQL 伺服器使用驗證外掛程式驗證用戶端連線。驗證給定連線的外掛程式可以要求將連線 (外部) 使用者視為不同的使用者,以進行權限檢查。這使外部使用者能夠成為第二個使用者的代理;也就是說,承擔第二個使用者的權限
外部使用者是「代理使用者」(可以偽裝或成為另一個使用者為人所知的使用者)。
第二個使用者是「被代理的使用者」(其身分和權限可以由代理使用者承擔的使用者)。
本節說明代理使用者功能如何運作。如需關於驗證外掛程式的一般資訊,請參閱第 8.2.17 節,「可插拔驗證」。如需關於特定外掛程式的資訊,請參閱第 8.4.1 節,「驗證外掛程式」。如需關於撰寫支援代理使用者的驗證外掛程式的資訊,請參閱在驗證外掛程式中實作代理使用者支援。
代理可以獲得的一個管理優勢是,DBA 可以設定具有一組權限的單一帳戶,然後啟用多個代理使用者來擁有這些權限,而無需將權限個別指派給每個使用者。作為代理使用者的替代方案,DBA 可能會發現角色提供了一種將使用者對應到特定命名權限集的合適方法。可以將給定的單一角色授予每個使用者,以便實際上被授予適當的權限集。請參閱第 8.2.10 節,「使用角色」。
若要讓給定的驗證外掛程式發生代理,必須滿足以下條件
必須支援代理,無論是外掛程式本身,還是由 MySQL 伺服器代表外掛程式。在後一種情況下,可能需要明確啟用伺服器支援;請參閱伺服器對代理使用者對應的支援。
必須設定外部代理使用者的帳戶,以便由外掛程式驗證。使用
CREATE USER
陳述式將帳戶與驗證外掛程式建立關聯,或使用ALTER USER
來變更其外掛程式。被代理使用者的帳戶必須存在,並且被授予代理使用者要承擔的權限。為此,請使用
CREATE USER
和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
'employee
。employee
這個名稱與 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
權限,才能讓外部使用者以另一個使用者的身分連線並擁有其權限。若要授予此權限,請使用 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 GRANT
和 REVOKE
語法擴充功能會像往常一樣運作。範例
-- 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_user
的GRANT 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
驗證外掛程式,並將 myuser
和 myuser_password
作為使用者名稱和密碼傳遞給它。
如果 ldap_auth
外掛程式在 LDAP 目錄中找不到 myuser_password
是 myuser
的正確密碼,驗證會失敗,伺服器會拒絕連線。
如果密碼正確,並且 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 |
+------------------+-------------------+
為求簡單,外部驗證不能是多層級的:在前面的範例中,不會考慮 developer
或 manager
的認證。但是,如果用戶端嘗試直接以 developer
或 manager
帳戶連線和驗證,則仍然會使用它們,這就是為什麼應保護這些被代理的帳戶免受直接登入 (請參閱防止直接登入被代理的帳戶)。
如果您打算建立預設代理使用者,請檢查是否有其他現有的 「符合任何使用者」帳戶優先於預設代理使用者,因為它們可能會阻止該使用者如預期般運作。
在前面的討論中,預設代理使用者帳戶在主機部分具有 ''
,這與任何主機都匹配。如果您設定了預設代理使用者,請務必同時檢查是否存在具有相同使用者部分且在主機部分具有 '%'
的非代理帳戶,因為 '%'
也與任何主機匹配,但根據伺服器在內部對帳戶列進行排序的規則,它的優先順序高於 ''
(請參閱章節 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
,也可能需要啟用外掛程式專用的系統變數,才能利用伺服器代理使用者對應支援對於已棄用的
mysql_native_password
外掛程式,請啟用mysql_native_password_proxy_users
。對於已棄用的
sha256_password
外掛程式,請啟用sha256_password_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_user
的 PROXY
權限,並且工作階段會以 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
。