?? 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 + -