分享到

简介

访问控制和用户管理是两个领域,随着系统内用户数量和不同数据库实体的增加,这两个领域会迅速变得复杂。管理各种数据库对象上的许多不同权限,确保具有相同职责的用户具有相同的访问级别,以及审计和缩小访问范围都会随着时间的推移变得更加困难。

为了帮助解决这个问题,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>';

例如,要向名为 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_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;

您还可以通过使用 ALL EXCEPT 告诉 MySQL 激活您的所有角色,但有特定例外

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

自 2013 年以来,Justin 一直在撰写关于数据库、Linux、基础设施和开发者工具的文章。他目前与妻子和两只兔子住在柏林。他通常不必以第三人称写作,这对所有相关方来说都是一种解脱。