Time:2019-8-15 21.42
Site:深圳科興科學院
Author: strivewang
摘要
- 第一部分是介紹Mysql創建用戶以及相應的權限介紹。
- 第二部分細節介紹了Mysql不同維度的權限控制
- 第三部分講解了權限控制
1. Mysql創建用戶
第一條語句的邏輯是創建一個用戶’user'@'%’,密碼是 password。用戶名是user, host是%,表示所有的ip
create user 'ua'@'%' identified by 'password';
第二條語句的邏輯是創建一個用戶’user'@'192.168.0.1’,密碼是 password。用戶名是user, host是192.168.0.1,表示所有的ip
create user 'ua'@'192.168.0.1' identified by 'password';
這條命令做了兩個動作:
- 磁盤上,往 mysql.user 表裏插入一行,由於沒有指定權限,所以這行數據上表示所有的權限字段都是 N。
- 內存上,往數組 acl_users 裏插入一個 acl_user 對象,這個對象的access 字段值爲 0 。
圖一就是用戶 ua 的狀態圖
2. 全局權限
2.1 授予全局權限
全局權限:作用於整個 MySQL 實例,這些權限信息保存在 Mysql 庫的 user 表中,如果需要給一個用戶賦予最高權限,就是:
grant all privileges on *.* to 'user'@'%' with grant option;
這個 grant 命令做了兩個動作:
- 磁盤上,將 mysql.user 表裏,用戶’user@’%’ 這一行所有表示權限的字段修改爲 ‘Y’
- 內存中,從數組acl_users 中找到這個用戶的對象,將acess值(權限位)修改爲二進制的 “全1”.
2.2 取消用戶全局權限:
revoke all privileges on *.* from 'user'@'%';
這個 grant 命令做了兩個動作:
- 磁盤上,將 mysql.user 表裏,用戶’user@’%’ 這一行所有表示權限的字段修改爲 ‘N’
- 內存中,從數組acl_users 中找到這個用戶的對象,將acess值(權限位)修改爲二進制的 “全0”.
3. DB權限
除了全局權限,Mysql也支持庫、表、列等權限的定義。
3.1 授予用戶指定庫權限
#授予ua用戶db1庫所有的權限
grant all privileges on db1.* to 'ua'@'%' with grant option;
基於庫的權限記錄保存在 mysql.db 中,在內存裏則保存在數組acl_dbs中,這個grant命令做了如下兩個操作:
- 磁盤上,往mysql.db 表中插入一行記錄,所有權限字段設置爲 “Y”。
- 內存裏, 增加一個對象到數組acl_dbs 中,這個對象的權限位設爲 “全1”。
下圖就是當前用戶 ua 在 DB表中的的權限狀態:
數據庫每次需要判斷一個用戶對一個數據庫讀寫權限的時候,都需要遍歷一次 acl_dbs 數組,根據User、host 和 db 找到匹配的對象,然後根據對象的權限位進行判斷。
grant 修改 db 權限的時候,對磁盤和內存是同時生效的。
4. 表權限、列權限
除了全局權限、DB級別的權限之外,Mysql還支持更細粒度的表權限和列權限。其中表權限定義在mysql.table_priv,列權限定義在mysql.columns_priv中。這兩種權限,組合起來存放在內存的Hash結構column_priv_hash中。
這兩種權限的命令如下:
create table db1.t1(id int, a int);
# 賦予用戶ua 庫db1的t1表權限
grant all privileges on db1.t1 to 'ua'@'%' with grant option;
# 賦予用戶ua 讀id、插入id,a列的權限
GRANT SELECT(id), INSERT (id,a) ON mydb.mytbl TO 'ua'@'%' with grant option;
和 db 權限類似,表、列的權限每次 grant 的時候都會修改數據表,也會同步修改內存中的 hash 結構。因此這兩個操作會馬上影響已存在的鏈接。
5. flush privileges 問題
既然 grant 每次執行完就是即時生效, 那爲什麼有時候需要執行 flush privileges 呢?
-
flush privileges 命令會清空 acl_users 數組,然後從 mysql.user 中重新讀取數據加載到內存當中,重新構造一個 acl_users 數組。換句話說就是以數據表中的數據爲準,將內存中的權限數組重新加載一邊。
-
其實每次 grant 之後是不需要執行 flush privileges 的,只有當內存中的數據權限和磁盤表中的數據不同的時候,才需要執行 flush privileges 。如果我們規範的使用 grant、revoke,就不需要執行 flush privileges 。
因此,正常情況下,執行完 grant 之後,就不需要執行 flush privileges 。
5.1 flush privileges 使用場景
從上面分析得出,使用 flush privileges 的場景,無非就是 內存中權限數據跟磁盤數據表權限數據不一致,需要使用 flush privileges 來同步內存中的權限數據。
這種數據不一致,往往都是不規則的命令造成的,比如直接操作 mysql.user 表等等。
通過下面的表來解釋一下不規範的操作導致的需要使用 flush privileges 來使權限數據一致。
client A 在T3 時刻已經通過操作 mysql.user表,刪除了 user=ua的用戶,但是 client B 在T4依然可以使用這個賬戶鏈接數據庫,client B 在T4能成功鏈接數據庫的原因就是內存中的 acl_users 中還有這個用戶,所以client B 在T4可以成功連接。在T5 使用了 flush privileges 命令之後,Client B 再鏈接,就會報錯。
所以,直接操作數據庫系統表是不規範的操作,就會導致內存中的權限數據和磁盤中的數據不一致。
還有更奇怪的現象如下圖4:
在T3時刻,通過直接操作 mysql.user表,直接刪除了數據表中的記錄,而內存中的數據還在,這就導致了下面這兩個問題:
T4時刻,賦予用戶權限失敗,這是因爲數據表中已經沒有了這個用戶。
T5時刻,再次創建該用戶失敗,這是因爲內存中依然存在該用戶。
總結一下Mysql 中權限的作用以及在內存中和磁盤中存在的位置,如圖5: