在服务器接受连接后,它将进入访问控制的第二阶段。对于您通过连接发出的每个请求,服务器将确定您要执行的操作,然后检查您的权限是否足够。这是特权列在授予权表中的作用。这些权限可以来自任何 user
、global_grants
、db
、tables_priv
、columns_priv
或 procs_priv
表。(您可能需要参考 第 8.2.3 节,「授予权表」,其中列出了每个授予权表中的列。)
user
和 global_grants
表授予全局权限。这些表中的行对于给定的帐户指示了帐户在全局基础上适用的权限,无论默认数据库是什么。例如,如果 user
表授予您 DELETE
权限,那么您可以从任何数据库的任何表中删除行。建议仅将权限授予需要它们的人,例如数据库管理员。对于其他用户,请将 user
表中的所有权限设置为 'N'
,并仅在更具体的级别上授予权限(例如特定的数据库、表、列或例程)。也可以在全局范围内授予数据库权限,但使用部分撤销来限制它们在特定数据库上的执行(请参阅 第 8.2.12 节,「使用部分撤销限制权限」)。
db
表授予数据库特定的权限。该表中的范围列值可以采取以下形式:
服务器将 db
表读入内存,并在读取 user
表时对其进行排序。服务器根据 Host
、Db
和 User
范围列对 db
表进行排序。与 user
表类似,排序将最具体的值放在最前面,将最不具体的值放在最后,并且当服务器查找匹配行时,它将使用找到的第一个匹配项。
tables_priv
、columns_priv
和 procs_priv
表授予表特定的、列特定的和例程特定的权限。这些表中的范围列值可以采取以下形式:
-
通配符
%
和_
可以在Host
列中使用。这些通配符的含义与使用LIKE
运算符进行模式匹配操作相同。 -
'%'
或空白的Host
值表示 “任何主机。” -
Db
、Table_name
、Column_name
和Routine_name
列不能包含通配符或为空。
服务器根据 Host
、Db
和 User
列对 tables_priv
、columns_priv
和 procs_priv
表进行排序。这类似于 db
表的排序,但更简单,因为只有 Host
列可以包含通配符。
服务器使用排序表来验证它收到的每个请求。对于需要管理权限的请求,例如SHUTDOWN
或RELOAD
,服务器仅检查user
和global_privilege
表,因为这些表指定了管理权限。服务器授予访问权限,如果账户的行在这些表中允许请求的操作,否则拒绝访问权限。例如,如果您想执行mysqladmin shutdown,但您的user
表行不授予SHUTDOWN
权限,那么服务器将拒绝访问权限,而不检查db
表。(后者表中没有Shutdown_priv
列,因此不需要检查它。)
对于数据库相关的请求(INSERT
、UPDATE
等),服务器首先检查用户的全局权限在user
表行中(减去部分撤销的权限限制)。如果行允许请求的操作,授予访问权限。如果user
表中的全局权限不足,服务器确定用户的数据库特定权限来自db
表:
-
服务器在
db
表中查找匹配的Host
、Db
和User
列。 -
服务器将
Host
和User
列与连接用户的主机名和 MySQL 用户名匹配。 -
服务器将
Db
列与用户想要访问的数据库匹配。 -
如果没有
Host
和User
的行,拒绝访问权限。
在确定了数据库特定权限后,服务器将其添加到user
表授予的全局权限中。如果结果允许请求的操作,授予访问权限。否则,服务器将检查用户的表和列权限在tables_priv
和columns_priv
表中,添加这些权限,并根据结果授予或拒绝访问权限。对于存储过程操作,服务器使用procs_priv
表,而不是tables_priv
和columns_priv
。
用布尔逻辑术语表达,前面的描述可以总结如下:
global privileges
OR database privileges
OR table privileges
OR column privileges
OR routine privileges
可能不明显的是,如果全局权限最初被发现不足以满足请求的操作,服务器为什么要将这些权限添加到数据库、表和列权限中。原因是,请求可能需要多种类型的权限。例如,如果您执行INSERT INTO ... SELECT
语句,您需要INSERT
和SELECT
权限。您的权限可能是user
表行授予一个全局权限,而db
表行授予另一个特定数据库的权限。在这种情况下,您拥有执行请求所需的权限,但服务器无法从您的全局或数据库权限中单独确定这一点。它必须基于组合权限做出访问控制决策。