8.2.7 访问控制,第二阶段:请求验证
服务器接受连接后,它将进入 Stage 2 的访问控制阶段。对于每个通过连接发送的请求,服务器将确定您想要执行的操作,然后检查您的权限是否足够。这是权限列在授权表中的地方。这些权限可以来自任何user
、global_grants
、db
、tables_priv
、columns_priv
或procs_priv
表中。您可能会发现,查看第8.2.3节,“授权表”,该表列出了每个授权表中的列,可以帮助您。
user
和global_grants
表授予全局权限。这些表中关于给定帐户的行表示该帐户在全局范围内的权限,无论默认数据库是什么。例如,如果user
表授予您DELETE
权限,您可以删除任何数据库中的任何表的任何行。为避免授予不必要的权限,建议只授予数据库管理员需要的权限。对于其他用户,留下user
表中的所有权限设置为'N'
,并在更具体的级别上授予权限(例如,特定的数据库、表、列或存储程序)。还可以授予数据库权限,但使用部分撤销来限制它们在特定的数据库中执行(查看第8.2.12节,“部分撤销使用的权限限制”)。
db
表授予数据库特定的权限。该表中的scope列的值可以采用以下形式:
服务器将 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
的行,访问被拒绝。
在确定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
表行授予另一个特定于相关数据库的权限。在这种情况下,您拥有必要的权限来执行请求,但是服务器不能从您的全局或数据库权限中确定这一点。它必须基于组合权限做出访问控制决策。