應用程式可以使用下列準則來執行基於 SQL 的稽核,將資料庫活動與 MySQL 帳戶連結。
MySQL 帳戶對應於 mysql.user 系統資料表中的資料列。當用戶端成功連線時,伺服器會將用戶端驗證至此資料表中的特定資料列。此資料列中的 User 和 Host 欄位值會唯一識別帳戶,並對應於 SQL 陳述式中撰寫帳戶名稱的 ' 格式。user_name'@'host_name'
用於驗證用戶端的帳戶會決定用戶端擁有的權限。通常,可以呼叫 CURRENT_USER() 函數來判斷用戶端使用者是哪個帳戶。其值是從帳戶的 user 資料表資料列的 User 和 Host 欄位所建構。
然而,在某些情況下,CURRENT_USER() 值對應的不是用戶端使用者,而是不同的帳戶。當權限檢查不是基於用戶端的帳戶時,就會發生這種情況
使用
SQL SECURITY DEFINER特性定義的預存常式 (程序和函數)使用
SQL SECURITY DEFINER特性定義的檢視觸發程序和事件
在這些情況下,權限檢查會針對 DEFINER 帳戶執行,而且 CURRENT_USER() 指的是該帳戶,而不是呼叫預存常式或檢視的使用者,或導致觸發程序啟動的用戶端帳戶。若要判斷呼叫使用者,您可以呼叫 USER() 函數,該函數會傳回一個值,指示用戶端提供的實際使用者名稱和用戶端連線的主機。然而,此值不一定會直接對應於 user 資料表中的帳戶,因為 USER() 值永遠不會包含萬用字元,而帳戶值 (由 CURRENT_USER() 傳回) 可能會包含使用者名稱和主機名稱萬用字元。
例如,空白使用者名稱會比對任何使用者,因此 ''@'localhost' 的帳戶可讓用戶端從本機主機以任何使用者名稱匿名連線。在此情況下,如果用戶端以本機主機的 user1 連線,USER() 和 CURRENT_USER() 會傳回不同的值
mysql> SELECT USER(), CURRENT_USER();
+-----------------+----------------+
| USER() | CURRENT_USER() |
+-----------------+----------------+
| user1@localhost | @localhost |
+-----------------+----------------+帳戶的主機名稱部分也可以包含萬用字元。如果主機名稱包含 '%' 或 '_' 模式字元,或是使用網路遮罩表示法,則該帳戶可供從多個主機連線的用戶端使用,而且 CURRENT_USER() 值不會指出哪個主機。例如,'user2'@'%.example.com' 帳戶可供 user2 從 example.com 網域中的任何主機連線使用。如果 user2 從 remote.example.com 連線,USER() 和 CURRENT_USER() 會傳回不同的值
mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER() | CURRENT_USER() |
+--------------------------+---------------------+
| user2@remote.example.com | user2@%.example.com |
+--------------------------+---------------------+如果應用程式必須為了使用者稽核而調用 USER() (例如,如果它在觸發器內執行稽核),但又必須能夠將 USER() 的值與 user 表中的帳戶關聯,則必須避免在 User 或 Host 欄位中使用萬用字元的帳戶。具體而言,不要允許 User 為空 (這會建立一個匿名使用者帳戶),並且不要在 Host 值中允許模式字元或網路遮罩表示法。所有帳戶都必須具有非空的 User 值和字面上的 Host 值。
針對先前的範例,應變更 ''@'localhost' 和 'user2'@'%.example.com' 帳戶,不要使用萬用字元。
RENAME USER ''@'localhost' TO 'user1'@'localhost';
RENAME USER 'user2'@'%.example.com' TO 'user2'@'remote.example.com';如果 user2 必須能夠從 example.com 網域中的多個主機連線,則每個主機都應該有一個單獨的帳戶。
若要從 CURRENT_USER() 或 USER() 值中提取使用者名稱或主機名稱部分,請使用 SUBSTRING_INDEX() 函數。
mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',1);
+---------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',1) |
+---------------------------------------+
| user1 |
+---------------------------------------+
mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',-1);
+----------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',-1) |
+----------------------------------------+
| localhost |
+----------------------------------------+