分享至

簡介

存取控制和使用者管理是兩個領域,隨著系統內使用者數量和不同資料庫實體的增加,它們可能會迅速變得複雜。管理各種資料庫物件上的許多不同權限、確保具有相同職責的使用者擁有相同的存取層級,以及稽核和縮小存取範圍,都會隨著時間的推移變得更加困難。

為了幫助解決這個問題,MySQL 有一個稱為「角色」的概念,它允許您將權限組合在給定的名稱下進行分組,讓您可以大量指派和修改設定。在本指南中,我們將介紹角色在 MySQL 中的運作方式,以及如何使用它們來更輕鬆地管理使用者的資料存取權。

指令

以下是我們將討論與管理 MySQL 角色相關的主要 SQL 指令。

  • CREATE ROLECREATE ROLE 指令在資料庫系統中定義一個新角色。
  • DROP ROLEDROP ROLE 指令的作用相反,它會刪除現有角色。
  • GRANTGRANT 指令有兩個與角色相關的不同用途:將權限新增至角色,以及將使用者帳戶新增為角色成員。
  • REVOKE:在角色的上下文中,REVOKE 指令會從角色中移除權限,也會從使用者帳戶中移除角色成員資格。
  • SHOW GRANTSSHOW GRANTS 指令會顯示給定使用者帳戶或角色的權限。
  • SET ROLESET ROLE 指令會變更使用者帳戶正在主動使用的角色。這讓您可以指定哪些權限集適用於該工作階段的帳戶。
  • SET DEFAULT ROLESET DEFAULT ROLE 指令定義當用戶端以特定使用者帳戶登入時,自動套用的角色。

必要權限

若要遵循本指南,您需要以下權限

  • CREATE ROLE
  • GRANT OPTION
  • CREATE USER(為另一個使用者設定預設角色)
  • ROLE_ADMIN(設定修改角色行為的系統變數)
  • SYSTEM_VARIABLES_ADMIN(設定修改角色行為的系統變數)

CREATE ROLE 權限是 CREATE USER 權限的較低版本,允許您建立和管理角色。已經擁有 CREATE USER 權限的帳戶會自動擁有管理角色所需的所有功能。

需要 GRANT OPTION 權限才能將權限指派給角色。您必須為想要指派給角色的任何權限啟用 GRANT OPTION

什麼是角色?

在 MySQL 中,角色是一個實體,其功能為權限的容器或集合。管理員可以將權限指派給角色,就像他們將權限指派給使用者帳戶一樣。然後,您可以將使用者帳戶新增為角色成員,允許這些帳戶存取與角色相關聯的權限。

基本上,角色的作用是將不同的相關權限捆綁在一起,以簡化權限管理。使用命名的權限群組,您可以管理更少、更容易理解的指派,而無需確保每個使用者都透過指派個別權限來獲得他們所需的確切存取層級。

這在指派存取層級時具有明顯的優勢,因為將 developersysadminfinanceteam 角色指派給使用者,比個別管理數十個權限更容易。這也使得一次調整多個帳戶的存取權變得快速。如果您為業務團隊建立新的資料庫,您可以授予 salesteam 角色對它的存取權,而不是追蹤每個應該擁有存取權的帳戶。

建立角色

如果您擁有具有 CREATE ROLE 權限的帳戶,您可以使用 CREATE ROLE 指令管理角色。

MySQL 角色的語法是什麼?

角色名稱必須遵循特定格式,MySQL 才會將其視為有效。在許多方面,它們都反映了用於定義 MySQL 使用者帳戶的格式,但有一些重要的差異。

角色遵循以下格式

'<role>'@'<host>'

與使用者一樣,角色也有兩個組成部分:角色名稱和用戶端連線的主機。但是,MySQL 解釋這些組成部分的方式有所不同。

對於角色,名稱的 '<role>' 部分永遠不能為空。角色沒有像使用者那樣的「匿名」概念。另一方面,省略 '<host>' 部分仍然是被允許的,MySQL 將使用 % 作為主機。但是,此上下文中的 % 被解釋為字面字元,而不是萬用字元。

實際上,這表示雖然角色名稱表面上與使用者帳戶名稱共享格式,但它們不會像使用者帳戶那樣進行任何類型的評估,而只是一個具有兩個組成部分的標籤。它們的名稱確實有兩個部分的原因是,您可以建立既可以用作使用者又可以用作角色的使用者帳戶。當用作使用者時,這些組成部分會受到使用者管理文章中描述的特殊評估規則的約束;當用作角色時,名稱只會使用字面組成部分名稱直接比對。

由於這些規則,在許多情況下,管理員選擇僅使用 '<role>' 組成部分來定義角色。這會導致 MySQL 將字面 % 字元替換為 '<host>' 組成部分,實際上使名稱的該部分不可見且無關緊要。如果您不打算將名稱同時用作使用者帳戶和角色,您可以執行相同的操作。

如何建立角色?

若要建立新角色,請使用 CREATE ROLE 指令。

基本語法如下所示

CREATE ROLE '<role>'@'<host>';

您也可以透過用逗號分隔每個角色名稱來同時建立多個角色

CREATE ROLE '<role_1>'@'<host>', '<role_2>'@'<host>', '<role_3>'@'<host>';

如果您指定的任何角色已存在於系統中,則指令將失敗並出現錯誤。

為了避免這種情況並使 MySQL 僅發出警告,您可以在 CREATE ROLE 指令後、角色名稱前包含 IF NOT EXISTS 子句

CREATE ROLE IF NOT EXISTS '<role>'@'<host>';

如上所述,許多時候管理員會省略角色名稱的 '<host>' 部分以簡化操作,隱式地將其設定為字面 % 字元。因此,在實務中,您的許多角色建立指令可能更像這樣

CREATE ROLE '<role>';

如何授予角色權限?

在建立新角色後,您的下一個優先事項通常是透過授予它們權限來使它們有意義。

您授予角色權限的方式與您授予使用者帳戶權限的方式相同。您提供您希望授予的確切權限,透過提供權限有效的資料庫和資料庫物件來指定範圍,以及應該被授予權限的實體 — 在這種情況下,是角色

GRANT <privileges> ON <database>.<object> TO '<role>'@'<host>';

例如,若要將 SELECT 權限授予名為 readapp 的角色,使其作用範圍為 appdb 資料庫及其包含的所有物件,您可以輸入

GRANT SELECT ON appdb.* TO 'readapp';

同樣地,您可以透過輸入以下內容,將寫入權限授予相同資料庫中名為 writeapp 的角色

GRANT SELECT,INSERT,UPDATE,DELETE ON appdb.* TO 'writeapp';

您可以像直接對使用者帳戶一樣,授予角色權限並從角色撤銷權限。因此,如果您需要調整您希望提供的存取層級,您可以隨時修改與角色相關聯的權限。

如何授予使用者角色成員資格?

在將權限新增至角色後,您可以開始將成員新增至角色,以授予他們相關聯的權限。

為此,MySQL 使用了與我們用於授予使用者和角色權限的 GRANT 相同的指令的不同形式。但是,這種新形式將角色新增至使用者,允許使用者帳戶存取授予角色的所有權限。

基本語法如下所示

GRANT '<role>'@'<host>' TO '<user>'@'<host>';

例如,如果 'reports'@'localhost' 使用者需要能夠從 appdb 資料庫讀取資料以產生報表,我們可以將 readapp 角色新增至使用者帳戶,授予它 select 權限

GRANT 'readapp' TO 'reports'@'localhost';

同樣地,若要讓 'appuser'@'localhost' 能夠管理同一資料庫中的資料,我們可以讓該使用者成為 writeapp 角色的成員

GRANT 'writeapp' TO 'appuser'@'localhost';

'appuser'@'localhost' 帳戶現在將能夠從資料庫插入、更新和移除資料。如果新的權限被新增至 writeapp 角色,'appuser'@'localhost' 帳戶將立即獲得這些權限。

如何自動授予每個使用者某些角色?

有時,您可能希望系統上的每個使用者都具有存取權的角色。您可以透過設定 mandatory_roles 變數來定義每個帳戶自動授予哪些角色。

若要修改 mandatory_roles 變數,您的使用者必須具有 ROLE_ADMINSYSTEM_VARIABLES_ADMIN 權限。您可以透過輸入以下內容來設定您希望授予每個使用者的角色

SET PERSIST mandatory_roles = '`<role_1>`@`<host>`, `<role_2>`@`<host>`, `<role_3>`@`<host>`';

在這裡,我們自動授予系統上的每個使用者三個角色。在設定系統變數時,mandatory_roles 的值必須是字串,因此我們將整個角色列表封裝在單引號中,並使用反引號來引號個別角色組成部分。

您無法將具有 SYSTEM_USER 權限的角色新增至 mandatory_roles 列表。這是一種安全措施,旨在確保系統上的並非所有工作階段都是自動系統工作階段。

如何使用來自角色的權限?

在您授予使用者帳戶角色成員資格後,您要如何使用它們?若要存取角色授予帳戶的權限,必須先啟用它。

檢視目前作用中的角色

在啟用新角色之前,您可以檢查目前使用者工作階段中作用中的角色。

若要檢視工作階段的作用中角色,請輸入

SELECT CURRENT_ROLE()

輸出將顯示您目前工作階段中作用中的零個或多個角色。與這些角色相關聯的權限將新增到您被允許執行的動作中。

如何為工作階段啟用角色

若要變更工作階段期間作用中的角色,請使用 SET ROLE 指令。您可以使用多種不同的方式使用此指令。

基本語法如下所示

SET ROLE '<rolename>'@'<host>';

這將啟用有問題的角色。請務必注意,SET ROLE 指令中未提及的任何先前作用中的角色現在都將被停用。

若要一次啟用多個角色,請用逗號分隔每個角色

SET ROLE '<role_1>'@'<host>', '<role_2>'@'<host>', '<role_3>'@'<host>';

若要啟用已授予您帳戶的所有角色,您可以指定 ALL 而不是特定角色

SET ROLE ALL;

您也可以告訴 MySQL 啟用您的所有角色,但使用 ALL EXCEPT 排除特定角色

SET ROLL ALL EXCEPT '<role_1>'@'<host>';

另一個選項是透過指定 NONE 來停用您帳戶上的所有角色

SET ROLE NONE

這將停用您使用者角色的工作階段,只讓您擁有專門指派給您使用者帳戶的權限。

若要返回為您的帳戶定義的預設角色列表,請使用 DEFAULT 關鍵字

SET ROLE DEFAULT

如何為使用者帳戶定義預設角色

當您以使用者身分登入時自動啟用的角色,以及當您使用 SET ROLE DEFAULT 時重新啟用的角色,都是可配置的。

若要定義預設會啟用的角色,請使用 SET DEFAULT ROLE 指令,其使用方式與 SET ROLE 指令類似

SET DEFAULT ROLE '<role_1>'@'<host>';

這將設定預設角色,這些角色將在您登入或使用 SET ROLE DEFAULT 時為您自己的帳戶啟用。

如果您的使用者具有 CREATE USER 權限,您可以設定其他帳戶的預設角色

SET DEFAULT ROLE ALL TO '<user>'@'<host>';

在這裡,我們指定 '<user>'@'<host>' 帳戶應在身份驗證時自動啟用其所有角色。

此語法也可以用於定義多個帳戶的預設角色,方法是用逗號分隔每個使用者

SET DEFAULT ROLE ALL TO '<user_1>'@'<host>', '<user_2>'@'<host>';

預設為所有使用者啟用所有角色

如果您希望 MySQL 伺服器上的每個帳戶預設都啟用其所有角色,您可以變更系統設定來執行此操作。

activate_all_roles_on_login 變數設定為 true 時,MySQL 會在登入時自動啟用與帳戶相關聯的所有角色。這會取代 SET DEFAULT ROLE 指定的設定。

若要啟用此功能,您必須具有 SYSTEM_VARIABLES_ADMINROLE_ADMIN 權限。透過輸入以下內容啟用此功能

SET PERSIST activate_all_roles_on_login = ON;

這將導致使用者帳戶在登入時自動啟用所有角色。但是,SET ROLE DEFAULT 仍允許您僅啟用與帳戶相關聯的預設角色。

顯示從角色獲得的現有權限

若要了解您的帳戶有哪些權限可用,您可以使用 SHOW GRANTS 指令。

若要檢查為使用者啟用的授權,請輸入

SHOW GRANTS FOR '<user>'@'<host>';

輸出將顯示直接指派給使用者帳戶的所有權限,以及使用者所屬的所有角色。

在了解帳戶所屬的角色後,您可以透過輸入以下內容來檢查該角色為使用者提供的權限

SHOW GRANTS FOR '<user>'@'<host>' USING '<role>'@'<host>';

例如,若要檢查 'reports'@'localhost' 使用者的權限,包括其透過 readapp 角色成員資格授予的權限,您可以使用

SHOW GRANTS FOR 'reports'@'localhost' USING 'readapp';

這將顯示明確授予 'reports'@'localhost' 使用者帳戶的所有權限,以及由 readapp 角色新增的權限。

從使用者撤銷角色

那麼,當您想要從使用者移除角色時會發生什麼事?與 GRANT 指令可以將新權限新增至使用者或角色,或將角色新增至使用者類似,REVOKE 指令可以從使用者或角色移除權限,也可以從使用者移除角色成員資格。

用於從使用者帳戶移除角色的基本語法如下所示

REVOKE '<role>' FROM '<user>'@'<host>';

在執行類似這樣的語句後,使用者將不再有權存取透過角色授予的權限。

舉例來說,我們可以透過輸入以下內容,從 'appuser'@'localhost' 使用者帳戶撤銷 writeapp 角色

REVOKE 'writeapp' FROM 'appuser'@'localhost';

但是,如果使用者透過其他方式被授予權限(直接授予或透過不同角色的成員資格授予),他們仍然可以存取該權限。因此,如果 'appuser'@'localhost' 使用者也是我們先前授予的 readapp 角色的成員,他們仍然會擁有 appdb 資料庫的 SELECT 權限。

結論

在 MySQL 資料庫中使用角色來分配權限,有助於簡化存取控制系統的管理負擔和複雜性。相較於直接授予許多不同的權限,使用角色能更容易確保具有相同職責的使用者擁有相同的權限。

同樣地,角色讓您可以明確表達權限授予背後的意圖。與其在沒有任何註解的情況下授予帳戶大量權限,仔細選擇的角色名稱可以幫助區分不同的存取原因。透過事先花時間建立和組織角色,從長遠來看,您管理使用者存取資料不同部分的能力將會更加直接。

常見問題解答

為了執行刷新權限操作,告訴伺服器重新載入授權表,您可以執行 FLUSH PRIVILEGES 陳述式。

這也可以透過執行 mysqladmin flush-privilegesmysqladmin reload 指令來完成。

您可以使用 ALLALL PRIVILEGES 簡寫,在特定範圍內為使用者指派完整權限。

以下語法會將您的使用者能夠執行的與 sales 資料庫相關的所有權限,授予 'salesadmin'@'localhost' 使用者。

GRANT ALL PRIVILEGES ON sales.* TO 'salesadmin'@'localhost';

若要將全域唯讀權限授予使用者,您可以針對範圍元件的資料庫和資料庫物件部分都使用萬用字元。

基本語法如下所示

GRANT SELECT ON *.* TO 'sally'@localhost';

若要將唯讀權限的範圍限制為單一資料庫,請將點號左側的萬用字元替換為資料庫名稱

GRANT SELECT ON account.* TO 'meredith'@'localhost';

同樣地,若要僅授予對資料庫中特定表格的存取權,請使用以下語法

GRANT SELECT ON account.revenue TO 'meredith'@'localhost';

若要在 MySQL 中建立新的 root 或超級使用者帳戶,您必須使用 GRANT ALL PRIVILEGES 陳述式,授予其對資料庫中所有內容的完整 root 存取權。

基本語法如下所示

GRANT ALL PRIVILEGES ON *.* TO 'user_name'@'localhost' WITH GRANT OPTION;

若要了解您的帳戶有哪些權限可用,您可以使用 SHOW GRANTS 指令。

若要檢查為使用者啟用的授權,請輸入

SHOW GRANTS FOR '<user>'@'<host>';

在了解帳戶所屬的角色後,您可以透過輸入以下內容來檢查該角色為使用者提供的權限

SHOW GRANTS FOR '<user>'@'<host>' USING '<role>'@'<host>';
關於作者
Justin Ellingwood

Justin Ellingwood

Justin 自 2013 年以來一直撰寫關於資料庫、Linux、基礎架構和開發人員工具的文章。他目前與妻子和兩隻兔子住在柏林。他通常不必以第三人稱寫作,這對所有相關人士來說都是一種解脫。