在服务器接受连接后,它将进入访问控制的第二阶段。对于您通过连接发出的每个请求,服务器将确定您要执行的操作,然后检查您的权限是否足够。这是特权列在授予权表中的作用。这些权限可以来自任何 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表行授予另一个特定数据库的权限。在这种情况下,您拥有执行请求所需的权限,但服务器无法从您的全局或数据库权限中单独确定这一点。它必须基于组合权限做出访问控制决策。