简介
访问控制和用户管理是两个随着系统中用户数量和不同数据库实体增加而迅速变得复杂的领域。管理各种数据库对象上的许多不同权限,确保具有相同职责的用户拥有相同的访问级别,以及审计和缩小访问范围,所有这些都会随着时间的推移变得更加困难。
为了解决这个问题,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;
您还可以通过使用 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_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
简写形式,以特定范围将完整权限分配给用户。
以下语法将授予 'salesadmin'@'localhost'
用户与 sales
数据库相关的、您用户能够授予的所有权限。
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>';