服务器接受连接后,将进入访问控制的阶段 2。对于您通过连接发出的每个请求,服务器都会确定您要执行的操作,然后检查您的权限是否足够。这就是授权表中的权限列发挥作用的地方。这些权限可以来自 user、global_grants、db、tables_priv、columns_priv 或 procs_priv 表中的任何一个。(您可能会发现参考第 8.2.3 节“授权表”会有所帮助,其中列出了每个授权表中存在的列。)
user 和 global_grants 表授予全局权限。给定帐户的这些表中的行指示在全局范围内应用的帐户权限,而不管默认数据库是什么。例如,如果 user 表授予您 DELETE 权限,则您可以删除服务器主机上任何数据库中任何表中的行。明智的做法是,仅向需要 user 表中权限的人员(例如数据库管理员)授予权限。对于其他用户,请将 user 表中的所有权限设置为 'N',并仅在更具体的级别(对于特定数据库、表、列或例程)授予权限。也可以全局授予数据库权限,但使用部分撤销来限制它们在特定数据库上的执行(请参阅第 8.2.12 节“使用部分撤销限制权限”)。
db 表授予特定于数据库的权限。此表中范围列的值可以采用以下形式
服务器在读取 user 表的同时,将 db 表读入内存并对其进行排序。服务器根据 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的行,则拒绝访问。
在确定了 db 表行授予的数据库特定权限后,服务器会将它们添加到 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 表行专门为相关数据库授予另一个权限。在这种情况下,您拥有执行请求所需的权限,但服务器无法仅从您的全局权限或数据库权限中判断出来。它必须根据组合权限做出访问控制决策。