一旦你建立了連接,服務器進入訪問控制的階段2。對在此連接上進來的每個請求,服務器檢查你想執行什么操作,然后檢查是否有足夠的權限來執行它。這正是在授權表中的權限列發揮作用的地方。這些權限可以來自user、db、host、tables_priv或columns_priv表。(你會發現參考5.7.2節,“權限系統工作原理”很有幫助,它列出了每個 授權表中呈現的列。)
user表在全局基礎上授予賦予你的權限,該權限不管當前的數據庫是什么均適用。例如,如果user表授予你DELETE權限, 你可以刪除在服務器主機上從任何數據庫刪除行!換句話說,user表權限是超級用戶權限。只把user表的權限授予超級用戶如服務器或數據庫主管是明智的。對其他用戶,你應該把在user表中的權限設成'N'并且僅在特定數據庫的基礎上授權。你可以為特定的數據庫、表或列授權。
db和host表授予數據庫特定的權限。在這些表中的范圍列的值可以采用以下方式:
- 通配符字符“%”并“_”可用于兩個表的Host和Db列。它們與用LIKE操作符執行的模式匹配操作具有相同的含義。如果授權時你想使用某個字符,必須使用反斜現引用。例如,要想在數據庫名中包括下劃線(‘_’),在GRANT語句中用‘\_’來指定。
- 在db表的'%'Host值意味著“任何主機”,在db表中空Host值意味著“對進一步的信息咨詢host表”(本節后面將描述的一個過程)。
- 在host表的'%'或空Host值意味著“任何主機”。
- 在兩個表中的'%'或空Db值意味著“任何數據庫”。
- 在兩個表中的空User值匹配匿名用戶。
db和host表在服務器啟動時被讀取并排序(同時它讀user表)。db表在Host、Db和User范圍列上排序,并且host表在Host和Db范圍列上排序。對于user表,首先根據最具體的值最后根據最不具體的值排序,并且當服務器尋找匹配條目時,它使用它找到的第一匹配。
tables_priv和columns_priv表授予表和列特定的權限。這些表的范圍列的值可以如下被指定:
- 通配符“%”并“_”可用在使用在兩個表的Host列。
- 在兩個表中的'%'或空Host意味著“任何主機”。
- 在兩個表中的Db、Table_name和Column_name列不能包含通配符或空。
tables_priv和columns_priv表根據Host、Db和User列被排序。這類似于db表的排序,因為只有Host列可以包含通配符,排序更簡單。
請求證實進程在下面描述。(如果你熟悉訪問檢查的源碼,你會注意到這里的描述與在代碼使用的算法略有不同。描述等價于代碼實際做的東西;不同處只是使解釋更簡單。)
對需要管理權限的請求(SHUTDOWN、RELOAD等等),服務器僅檢查user表條目,因為那是唯一指定管理權限的表。如果行許可請求的操作,訪問被授權,否則拒絕。例如,如果你想要執行mysqladmin shutdown,但是由于user表行沒有為你授予HUTDOWN權限,甚至不用檢查db或host表就拒絕你的訪問。(因為它們不包含hutdown_priv行列,沒有這樣做的必要。)
對數據庫有關的請求(INSERT、UPDATE等等),服務器首先通過查找user表行來檢查用戶的全局(超級用戶)權限。如果行允許請求的操作,訪問被授權。如果在user表中全局權限不夠,服務器通過檢查db和host表確定特定的用戶數據庫權限:
- 服務器在db表的Host、Db和User列上查找匹配。Host和User對應連接用戶的主機名和MySQL用戶名。Db列對應用戶想要訪問的數據庫。如果沒有Host和User的行,訪問被拒絕。
- 如果db表中有匹配的行而且它的Host列不是空的,該行定義用戶的數據庫特定的權限。
- 如果匹配的db表的行的Host列是空的,它表示host表列舉被允許訪問數據庫的主機。在這種情況下,在host表中作進一步查找以發現Host和Db列上的匹配。如果沒有host表行匹配,訪問被拒絕。如果有匹配,用戶數據庫特定的權限以在db和host表的行的權限,即在兩個行都是'Y'的權限的交集(而不是并集!)計算。(這樣你可以授予在db表行中的一般權限,然后用host表行按主機主機為基礎有選擇地限制它們。)
在確定了由db和host表行授予的數據庫特定的權限后,服務器把他們加到由user表授予的全局權限中。如果結果允許請求的操作,訪問被授權。否則,服務器檢查在tables_priv和columns_priv表中的用戶的表和列權限并把它們加到用戶權限中。基于此結果允許或拒絕訪問。
用布爾術語表示,前面關于用戶權限如何計算的描述可以這樣總結:
global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
它可能不明顯,為什么呢,如果全局user行的權限最初發現對請求的操作不夠,服務器以后把這些權限加到數據庫、表并列的特定權限。原因是請求可能要求超過一種類型的權限。例如,如果你執行INSERT INTO ... SELECT語句,你就需要INSERT和SELECT權限。你的權限必須是user表行授予一個權限而db表行授予另一個權限。在這種情況下,你有必要的權限執行請求,但是服務器不能自己把兩個表區別開來;兩個行授予的權限必須組合起來。
host表不受GRANT或REVOKE語句的影響,因此在大多數MySQL安裝中沒有使用。如果你直接修改它,你可以用于某種專門目的,例如用來維護安全服務器列表。例如,在TcX,host表包含在本地網絡上所有的機器的表。這些表被授予所有的權限。
你也可以使用host表指定不安全的主機。假定你有一臺機器public.your.domain,它位于你認為不安全的公共區域,你可以用下列的host表條目允許除了那臺機器外的網絡上所有主機的訪問:
+--------------------+----+-
| Host | Db | ...
+--------------------+----+-
| public.your.domain | % | ... (all privileges set to 'N')
| %.your.domain | % | ... (all privileges set to 'Y')
+--------------------+----+-
當然,一定要測試授權表中的行(例如,使用SHOW GRANTS或mysqlaccess),確保你的訪問權限實際按你期望的方式被設置。