📄 manual_privilege_system.html
字号:
<p>既然你能在<code>Host</code>字段使用IP通配符值(例如,<code>'144.155.166.%'</code>匹配在一个子网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机为<code>144.155.166.somewhere.com</code>。为了阻止这样的企图,<strong>MySQL</strong>不允许匹配以数字和一个点起始的主机名,这样,如果你用一个命名为类似<code>1.2.foo.com</code>的主机,它的名字决不会匹配授权表中<code>Host</code>列。只有一个IP数字能匹配IP通配符值。
</p>
<p>一个到来的连接可以被在<code>user</code>表中的超过一个条目匹配。例如,一个由<code>fred</code>从<code>thomas.loc.gov</code>的连接匹配多个条目如上所述。如果超过一个匹配,服务器怎么选择使用哪个条目呢?服务器在启动时读入<code>user</code>表后通过排序来解决这个问题,然后当一个用户试图连接时,以排序的顺序浏览条目,第一个匹配的条目被使用。
</p>
<p><code>user</code>表排序工作如下,假定<code>user</code>表看起来像这样:
</p>
<pre>
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ...
| % | jeffrey | ...
| localhost | root | ...
| localhost | | ...
+-----------+----------+-
</pre>
<p>当服务器在表中读取时,它以最特定的<code>Host</code>值为先的次序排列(<code>'%'</code>在<code>Host</code>列里意味着“任何主机”并且是最不特定的)。有相同<code>Host</code>值的条目以最特定的<code>User</code>值为先的次序排列(一个空白<code>User</code>值意味着“任何用户”并且是最不特定的)。最终排序的<code>user</code>表看起来像这样:
</p>
<pre>
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | jeffrey | ...
| % | root | ...
+-----------+----------+-
</pre>
<p><a NAME="IDX133"></a>当一个连接被尝试时,服务器浏览排序的条目并使用找到的第一个匹配。对于由<code>jeffrey</code>从<code>localhost</code>的一个连接,在<code>Host</code>列的<code>'localhost'</code>条目首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。(<code>'%'/'jeffrey'</code>条目也将匹配,但是它不是在表中的第一匹配。)</p>
<p>这是另外一个例子。假定<code>user</code>桌子看起来像这样: </p>
<pre>
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| % | jeffrey | ...
| thomas.loc.gov | | ...
+----------------+----------+-
</pre>
<p>排序后的表看起来像这样: </p>
<pre>
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| thomas.loc.gov | | ...
| % | jeffrey | ...
+----------------+----------+-
</pre>
<p>一个由<code>jeffrey</code>从<code>thomas.loc.gov</code>的连接被第一个条目匹配,而一个由<code>jeffrey</code>从<code>whitehouse.gov</code>的连接被第二个匹配。
</p>
<p>普遍的误解是认为,对一个给定的用户名,当服务器试图对连接寻找匹配时,明确命名那个用户的所有条目将首先被使用。这明显不是事实。先前的例子说明了这点,在那里一个由<code>jeffrey</code>从<code>thomas.loc.gov</code>的连接没被包含<code>'jeffrey'</code>作为<code>User</code>字段值的条目匹配,但是由没有用户名的题目匹配!
</p>
<p>如果你有服务器连接的问题,打印出<code>user</code>表并且手工排序它看看第一个匹配在哪儿进行。
</p>
<h2><a NAME="Request_access" HREF="manual_toc.html#Request_access">6.8
存取控制,阶段2:请求证实</a></h2>
<p>一旦你建立了一个连接,服务器进入阶段2。对在此连接上进来的每个请求,服务器检查你是否有足够的权限来执行它,它基于你希望执行的操作类型。这正是在授权表中的权限字段发挥作用的地方。这些权限可以来子<code>user</code>、<code>db</code>、<code>host</code>、<code>tables_priv</code>或<code>columns_priv</code>表的任何一个。授权表用<code>GRANT</code>和<code>REVOKE</code>命令操作。见<a HREF="manual_Reference.html#GRANT">7.26<code> GRANT</code>和<code>REVOKE</code> 句法</a>。(你可以发觉参考<a HREF="manual_Privilege_system.html#Privileges">6.6 权限系统怎样工作</a>很有帮助,它列出了在每个权限表中呈现的字段。)</p>
<p><code>user</code>表在一个全局基础上授予赋予你的权限,该权限不管当前的数据库是什么均适用。例如,如果<code>user</code>表授予你<strong>delete</strong>权限,
你可以删除在服务器主机上从任何数据库删除行!换句话说,<code>user</code>表权限是超级用户权限。只把<code>user</code>表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户,你应该把在<code>user</code>表中的权限设成<code>'N'</code>并且仅在一个特定数据库的基础上授权,
使用<code>db</code>和<code>host</code>表。 </p>
<p><a NAME="IDX136"></a><code>db</code>和<code>host</code>表授予数据库特定的权限。在范围字段的值可以如下被指定:
<ul>
<li>通配符字符<samp>“%”</samp>和<samp>“_”</samp>可被用于两个表的<code>Host</code>和<code>Db</code>字段。
</li>
<li>在<code>db</code>表的<code>'%'Host</code>值意味着“任何主机”,在<code>db</code>表中一个空白<code>Host</code>值意味着“对进一步的信息咨询<code>host</code>表”。</li>
<li>在<code>host</code>表的一个<code>'%'</code>或空白<code>Host</code>值意味着“任何主机”。</li>
<li>在两个表中的一个<code>'%'</code>或空白<code>Db</code>值意味着“任何数据库”。</li>
<li>在两个表中的一个空白<code>User</code>值匹配匿名用户。 </li>
</ul>
<p><a NAME="IDX139"></a><code>db</code>和<code>host</code>表在服务器启动时被读取和排序(同时它读<code>user</code>表)。<code>db</code>表在<code>Host</code>、<code>Db</code>和<code>User</code>范围字段上排序,并且<code>host</code>表在<code>Host</code>和<code>Db</code>范围字段上排序。对于<code>user</code>表,排序首先放置最特定的值然后最后最不特定的值,并且当服务器寻找匹配入条目时,它使用它找到的第一个匹配。
</p>
<p><code>tables_priv</code>和<code>columns_priv</code>表授予表和列特定的权限。在范围字段的值可以如下被指定:
<ul>
<li>通配符<samp>“%”</samp>和<samp>“_”</samp>可用在使用在两个表的<code>Host</code>字段。
</li>
<li>在两个表中的一个<code>'%'</code>或空白<code>Host</code>意味着“任何主机”。</li>
<li>在两个表中的<code>Db</code>、<code>Table_name</code>和<code>Column_name</code>字段不能包含通配符或空白。
</li>
</ul>
<p><code>tables_priv</code>和<code>columns_priv</code>表在<code>Host</code>、<code>Db</code>和<code>User</code>字段上被排序。这类似于<code>db</code>表的排序,尽管因为只有<code>Host</code>字段可以包含通配符,但排序更简单。
</p>
<p>请求证实进程在下面描述。(如果你熟悉存取检查的源代码,你会注意到这里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;它只是不同于使解释更简单。)</p>
<p>对管理请求(<strong>shutdown</strong>、<strong>reload</strong>等等),服务器仅检查<code>user</code>表条目,因为那是唯一指定管理权限的表。如果条目许可请求的操作,存取被授权了,否则拒绝。例如,如果你想要执行<code>mysqladmin
shutdown</code>,但是你的<code>user</code>表条目没有为你授予<strong>shutdown</strong>权限,存取甚至不用检查<code>db</code>或<code>host</code>表就被拒绝。(因为他们不包含<code>Shutdown_priv</code>行列,没有这样做的必要。)</p>
<p>对数据库有关的请求(<strong>insert</strong>、<strong>update</strong>等等),服务器首先通过查找<code>user</code>表条目来检查用户的全局(超级用户)权限。如果条目允许请求的操作,存取被授权。如果在<code>user</code>表中全局权限不够,服务器通过检查<code>db</code>和<code>host</code>表确定特定的用户数据库权限:
<ol>
<li>服务器在<code>db</code>表的<code>Host</code>、<code>Db</code>和<code>User</code>字段上查找一个匹配。
<code>Host</code>和<code>User</code>对应连接用户的主机名和<strong>MySQL</strong>用户名。<code>Db</code>字段对应用户想要存取的数据库。如果没有<code>Host</code>和<code>User</code>的条目,存取被拒绝。
</li>
<li>如果<code>db</code>表中的条目有一个匹配而且它的<code>Host</code>字段不是空白的,该条目定义用户的数据库特定的权限。
</li>
<li>如果匹配的<code>db</code>表的条目的<code>Host</code>字段是空白的,它表示<code>host</code>表列举主机应该被允许存取数据库的主机。在这种情况下,在<code>host</code>表中作进一步查找以发现<code>Host</code>和<code>Db</code>字段上的匹配。如果没有<code>host</code>表条目匹配,存取被拒绝。如果有匹配,用户数据库特定的权限以在<code>db</code>和<code>host</code>表的条目的权限,即在两个条目都是<code>'Y'</code>的权限的交集(<em>而不是</em>并集!)计算。(这样你可以授予在<code>db</code>表条目中的一般权限,然后用<code>host</code>表条目按一个主机一个主机为基础地有选择地限制它们。)</li>
</ol>
<p>在确定了由<code>db</code>和<code>host</code>表条目授予的数据库特定的权限后,服务器把他们加到由<code>user</code>表授予的全局权限中。如果结果允许请求的操作,存取被授权。否则,服务器检查在<code>tables_priv</code>和<code>columns_priv</code>表中的用户的表和列权限并把它们加到用户权限中。基于此结果允许或拒绝存取。
</p>
<p>用布尔术语表示,前面关于一个用户权限如何计算的描述可以这样总结:
</p>
<pre>global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
</pre>
<p>它可能不明显,为什么呢,如果全局<code>user</code>条目的权限最初发现对请求的操作不够,服务器以后把这些权限加到数据库、表和列的特定权限。原因是一个请求可能要求超过一种类型的权限。例如,如果你执行一个<code>INSERT
... SELECT</code>语句,你就都要<strong>insert</strong>和<strong>select</strong>权限。你的权限必须如此以便<code>user</code>表条目授予一个权限而<code>db</code>表条目授予另一个。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把两个表区别开来;两个条目授予的权限必须组合起来。
</p>
<p><code>host</code>表能被用来维护一个“安全”服务器列表。在TcX,<code>host</code>表包含一个在本地的网络上所有的机器的表,这些被授予所有的权限。
</p>
<p>你也可以使用<code>host</code>表指定<em>不</em>安全的主机。假定你有一台机器<code>public.your.domain</code>,它位于你不认为是安全的一个公共区域,你可以用下列的<code>host</code>表条目子允许除了那台机器外的网络上所有主机的存取:
</p>
<pre>
+--------------------+----+-
| Host | Db | ...
+--------------------+----+-
| public.your.domain | % | ... (所有权限设为 'N')
| %.your.domain | % | ... (所有权限设为 'Y')
+--------------------+----+-
</pre>
<p>当然,你应该总是测试你在授权表中的条目(例如,使用<code>mysqlaccess</code>)让你确保你的存取权限实际上以你认为的方式被设置。
</p>
<h2><a NAME="Privilege_changes" HREF="manual_toc.html#Privilege_changes">6.9
权限更改何时生效</a></h2>
<p>当<code>mysqld</code>启动时,所有的授权表内容被读进存储器并且从那点生效。
</p>
<p>用<code>GRANT</code>、REVOKE或<code>SET PASSWORD</code>对授权表施行的修改会立即被服务器注意到。
</p>
<p>如果你手工地修改授权表(使用<code>INSERT</code>、UPDATE等等),你应该执行一个<code>FLUSH
PRIVILEGES</code>语句或运行<code>mysqladmin flush-privileges</code>告诉服务器再装载授权表,否则你的改变将<em>不生效</em>,除非你重启服务器。
</p>
<p>当服务器注意到授权表被改变了时,现存的客户连接有如下影响:
<ul>
<li>表和列权限在客户的下一次请求时生效。 </li>
<li>数据库权限改变在下一个<code>USE db_name</code>命令生效。 </li>
</ul>
<p>全局权限的改变和口令改变在下一次客户连接时生效。 </p>
<h2><a NAME="Default_privileges" HREF="manual_toc.html#Default_privileges">6.10
建立初始的MySQL权限</a></h2>
<p>在安装<strong>MySQL</strong>后,你通过运行<code>scripts/mysql_install_db</code>安装初始的存取权限。见<a HREF="manual_Installing.html#Quick_install">4.7.1 快速安装概述</a>。 <code>scripts/mysql_install_db</code>脚本启动<code>mysqld</code>服务器,然后初始化授权表,包含下列权限集合:
<ul>
<li><strong>MySQL</strong> <code>root</code>用户作为可做任何事情的一个超级用户被创造。连接必须由本地主机发出。<strong>注意</strong>:出世的<code>root</code>口令是空的,因此任何人能以<code>root</code>而<em>没有一个口令</em>进行连接并且被授予所有权限。
</li>
<li><a NAME="IDX145"></a>一个匿名用户被创造,他可对有<code>一个'test'</code>或以<code>'test_'</code>开始的名字的数据库做任何时期事情,连接必须由本地主机发出。这意味着任何本地用户能连接并且视为匿名用户。
</li>
<li>其他权限被拒绝。例如,一般用户不能使用<code>mysqladmin shutdown</code>或<code>mysqladmin
processlist</code>。 </li>
</ul>
<p><strong>注意:</strong>对Win32的初始权限是不同的。见<a HREF="manual_Installing.html#Win32_running">4.12.4 在Win32上运行MySQL</a>。 </p>
<p>既然你的安装初始时广开大门,你首先应该做的事情之一是为<strong>MySQL</strong>
<code>root</code>用户指定一个口令。你可以做如下(注意,你使用<code>PASSWORD()</code>函数指定口令):
</p>
<pre>shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
WHERE user='root';
mysql> FLUSH PRIVILEGES;
</pre>
<p>在<strong>MySQL</strong> 3.22和以上版本中,你可以使用<code>SET PASSWORD</code>语句:
</p>
<pre>shell> mysql -u root mysql
mysql> SET PASSWORD FOR root=PASSWORD('new_password');
</pre>
<p>设置口令的另一种方法是使用<code>mysqladmin</code>命令: </p>
<pre>shell> mysqladmin -u root password new_password
</pre>
<p>注意:如果你使用第一种方法在<code>user</code>表里直接更新口令,你必须告诉服务器再次读入授权表(用<code>FLUSH
PRIVILEGES</code>),因为否则改变将不被注意到。 </p>
<p>一旦<code>root</code>口令被设置,此后当你作为<code>root</code>与服务器连接时,你必须供应那个口令。
</p>
<p>你可能希望让<code>root</code>口令为空白以便当你施行附加的安装时,你不需要指定它或测试,但是保证在任何真实的生产工作中使用你的安装之前,设置它。
</p>
<p>看看<code>scripts/mysql_install_db</code>脚本,看它如何安装缺省的权限。你可用它作为一个研究如何增加其他用户的基础。
</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -