分享到

简介

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

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

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