简介
访问控制 和用户管理是两个可能随着系统中用户数量和不同数据库实体数量的增加而变得复杂的领域。管理各种数据库对象上的许多不同的权限,确保具有相同职责的用户拥有相同的访问级别,以及审核和缩小访问范围,随着时间的推移都会变得更加困难。
为了帮助解决这个问题,MySQL 有一个名为“角色”的概念,它允许您将一组权限捆绑在一个给定的名称下,以便您可以批量分配和修改设置。在本指南中,我们将介绍角色在 MySQL 中的工作原理以及如何使用它们来更轻松地管理用户的数据库访问权限。
命令
以下是我们将讨论的与管理 MySQL 角色相关的主要 SQL 命令。
CREATE ROLE
:CREATE ROLE
命令在数据库系统中定义一个新角色。DROP ROLE
:DROP ROLE
命令执行相反的操作,删除现有角色。GRANT
:GRANT
命令与角色有两个不同的目的:向角色添加权限以及将用户帐户添加为角色的成员。REVOKE
:在角色的上下文中,REVOKE
命令从角色中删除权限,还从用户帐户中删除角色成员资格。SHOW GRANTS
:SHOW GRANTS
命令显示给定用户帐户或角色的权限。SET ROLE
:SET ROLE
命令更改用户帐户正在积极使用的角色。这允许您指定哪些权限集适用于会话的帐户。SET DEFAULT ROLE
:SET DEFAULT ROLE
命令定义客户端以特定用户帐户登录时自动应用的角色。
所需权限
要按照本指南进行操作,您需要以下权限
CREATE ROLE
GRANT OPTION
CREATE USER
(为另一个用户设置默认角色)ROLE_ADMIN
(设置修改角色行为的系统变量)SYSTEM_VARIABLES_ADMIN
(设置修改角色行为的系统变量)
CREATE ROLE
权限是 CREATE USER
权限的较低版本,允许您创建和管理角色。已经拥有 CREATE USER
权限的帐户会自动拥有管理角色所需的所有功能。
要将权限分配给角色,需要 GRANT OPTION
权限。您必须为要分配给角色的任何权限启用 GRANT OPTION
。
什么是角色?
在 MySQL 中,角色 是充当权限容器或集合的实体。管理员可以向角色分配权限,就像他们向用户帐户分配权限一样。然后,您可以将用户帐户添加为角色的成员,使这些帐户能够访问与角色关联的权限。
基本上,角色充当将不同的相关权限捆绑在一起以简化权限管理的方法。与其通过分配单个权限来确保每个用户都拥有他们所需的精确访问级别,不如使用命名权限组,这样可以管理更少、更容易理解的分配。
当分配访问级别时,这具有明显的优势,因为将 developer
、sysadmin
或 financeteam
角色分配给用户比分别管理数十个权限更容易。它还使您可以快速调整对多个帐户的访问权限。如果您为销售团队创建一个新数据库,您可以向 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>';
例如,要授予名为 readapp
的角色对 appdb
数据库及其包含的所有对象的 SELECT
权限,您可以键入
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
角色,从而授予其选择权限
GRANT 'readapp' TO 'reports'@'localhost';
同样,要授予 'appuser'@'localhost'
用户管理同一数据库中数据的权限,我们可以让该用户成为 writeapp
角色的成员
GRANT 'writeapp' TO 'appuser'@'localhost';
现在,'appuser'@'localhost'
帐户将能够插入、更新和删除数据库中的数据。如果向 writeapp
角色添加了新权限,'appuser'@'localhost'
帐户将立即获得这些权限。
如何自动授予每个用户某些角色?
有时,您可能希望系统上的每个用户都能够访问某些角色。您可以通过设置 mandatory_roles
变量来定义每个帐户自动授予哪些角色。
要修改 mandatory_roles
变量,您的用户必须具有 ROLE_ADMIN
和 SYSTEM_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_ADMIN
和 ROLE_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-privileges 或 mysqladmin reload 命令来完成。
您可以使用 ALL
或 ALL 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';
要创建新的 root 用户(或超级用户帐户)在 MySQL 中,您必须使用 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>';