角色(Role),可以认为是一些权限的集合,一直是存在各个数据库中,比如Oracle、SQL Server、OceanBase等,MySQL 自从 8.0 release 才引入角色这个概念。
为用户赋予统一的角色,即把一个带有某些权限集合的角色分配给一个用户,那该用户就拥有了该角色所包含的所有权限,权限的修改直接通过角色来进行,无需为每个用户单独授权,大大的方便了权限管理。
从 CREATE USER 的 help 语法解释中发现,其不仅可以创建新的 MySQL 帐户,还支持为新帐户建立身份验证、SSL/TLS、资源限制和密码管理属性,并控制帐户最初是锁定还是解锁。
那么,缺省选项默认创建的用户是怎么样的呢?
mysql> CREATE USER kuzma IDENTIFIED BY 'iamkuzma';
Query OK, 0 rows affected (0.07 sec)
mysql> select * from mysql.user where User="kuzma"\G
*************************** 1. row ***************************
Host: %
User: kuzma
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher: 0x
x509_issuer: 0x
x509_subject: 0x
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string: *E2D9547BC3A2AD2EEC6BE9636489AC973656EEB9
password_expired: N
password_last_changed: 2022-10-05 17:41:06
password_lifetime: NULL
account_locked: N
1 row in set (0.06 sec)
如上,在 CREATE USER 后会在 mysql.user 系统表中注册相关用户信息,未指定的属性设置为其默认值:
首次创建的帐户没有权限,xxx_priv都为NONE,默认未设置用户权限,若需要分配权限,另外的通过 GRANT 语句为用户授权。
若要删除用户,DROP USER 'kuzma'@'%'; 注意指定用户名和主机名。
# 将密码标记为过期,用户在第一次连接到服务器时必须选择一个新密码
CREATE USER 'kuzma'@'localhost' PASSWORD EXPIRE;
CREATE USER 'kuzma'@'localhost' PASSWORD EXPIRE DEFAULT;
CREATE USER 'kuzma'@'localhost' PASSWORD EXPIRE NEVER;
CREATE USER 'kuzma'@'localhost' PASSWORD EXPIRE INTERVAL 180 DAY;
# 指定身份验证插件,及明文密码值
CREATE USER 'kuzma'@'localhost'
IDENTIFIED WITH mysql_native_password BY 'iamkuzma';
tls_option: {
SSL
| X509
| CIPHER 'cipher'
| ISSUER 'issuer'
| SUBJECT 'subject'
}
CREATE USER 'kuzma'@'localhost' REQUIRE NONE;
CREATE USER 'kuzma'@'localhost' REQUIRE SSL;
resource_option: {
MAX_QUERIES_PER_HOUR count # 允许该用户每小时多少查询
| MAX_UPDATES_PER_HOUR count # 允许该用户每小时多少更新
| MAX_CONNECTIONS_PER_HOUR count # 允许该用户每小时多少连接到服务器
| MAX_USER_CONNECTIONS count # 限制该用户同时连接到服务器的最大数量
}
CREATE USER 'kuzma'@'localhost' WITH MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
如果count为0(默认值),表示该用户没有限制。通常生产用户不会在数据库层做资源限制,但某些特殊用户特殊场景下,可通过进行资源限制实现限流。
CREATE USER 和 ALTER USER 中使用 ACCOUNT LOCK 和 ACCOUNT UNLOCK 选项支持用户的锁定和解锁;
常见场景:数据库、业务迁移,用户切新改造等,通过对用户的锁定和解锁,实现对业务连接控制。
使用 GRANT 给用户授权,REVOKE 给用户撤权(需要操作者拥有 GRANT OPTION 权限)。支持用户对库、表、列、存储过程、代理用户
# 授权[kuzma_write]用户{查询、插入、更新、删除}所有库表(*表示所有,db1.*表示db1库下的所有表)
GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO kuzma_write;
REVOKE DELETE ON *.* FROM 'kuzma_write'@'%';
GRANT SELECT (col1), INSERT (col1, col2) ON db1.tbl2 TO 'xxx_user'@'xxx_host';
GRANT CREATE ROUTINE ON db1.* TO 'xxx_user'@'xxx_host';
GRANT EXECUTE ON PROCEDURE db1.proc2 TO 'xxx_user'@'xxx_host';
GRANT PROXY ON 'localuser'@'localhost' TO 'xxx_user'@'xxx_host';
权限元数据存储位置:
权限类型
元数据存储-系统表
用户全局权限
mysql.user
数据库(DB)权限
mysql.db
表(table)权限
mysql.tables_priv
列(columns)权限
mysql.columns_priv
routine-level(procedures and functions)权限
mysql.procs_priv
代理(proxy)用户权限
mysql.proxies_priv
Tips:值得注意的是,在某些情况下,无论是 CREATE|ALTER USER 还是 GRANT 都可能会记录在服务器日志中或客户端的历史文件中,例如 ~/.mysql_history,这就意味着任何有权读取该信息的人都可以读取明文密码,这不就暴露了吗。
服务器级别角色:
数据库级别角色:
应用程序角色:
用户:
# 创建登录名[stu],并为登录名指定用户[student_user]
create user student_user for login stu;
create role student_role;
grant select, update, insert on db_book to student_role;
exec sp_addrolemember
@rolename='student_role',
@membername='student_user';
角色管理:
用户管理:
# 1.创建角色:创建三个角色,分别作为[app_db]的owner、read、write角色
CREATE ROLE 'app_owner', 'app_read', 'app_write';
GRANT ALL ON app_db.* TO 'app_owner';
GRANT SELECT ON app_db.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';
CREATE USER admin_user IDENTIFIED BY 'xxx_pass1';
CREATE USER read_user1 IDENTIFIED BY 'xxx_pass2';
CREATE USER read_user2 IDENTIFIED BY 'xxx_pass3';
CREATE USER rw_user1 IDENTIFIED BY 'xxx_pass4';
GRANT 'app_owner' TO admin_user;
GRANT 'app_read' TO read_user1, read_user2;
GRANT 'app_read', 'app_write' TO rw_user1;
mysql> show grants for app_read;
+----------------------------------------------+
| Grants for app_read@% |
+----------------------------------------------+
| GRANT USAGE ON *.* TO `app_read`@`%` |
| GRANT SELECT ON `app_db`.* TO `app_read`@`%` |
+----------------------------------------------+
2 rows in set (0.07 sec)
mysql> show grants for rw_user1;
+--------------------------------------------------------+
| Grants for rw_user1@% |
+--------------------------------------------------------+
| GRANT USAGE ON *.* TO `rw_user1`@`%` |
| GRANT `app_read`@`%`,`app_write`@`%` TO `rw_user1`@`%` |
+--------------------------------------------------------+
2 rows in set (0.06 sec)
这就结束了?
# 使用 [read_user1] 用户登录
$ mysql -u read_user1 -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_ROLE();
+----------------+
| CURRENT_ROLE() |
+----------------+
| NONE |
+----------------+
1 row in set (0.00 sec)
当然,没有结束,默认情况前面创建的角色并未被激活,最后一步是还需要“激活角色”:
# 5.激活角色:即设置用户的默认角色,前提是用户有分配角色(前第4步)
SET DEFAULT ROLE 'app_owner' TO admin_user;
SET DEFAULT ROLE ALL TO admin_user, read_user1, read_user2, rw_user1;
mysql> select * from mysql.default_roles;
+------+------------+-------------------+-------------------+
| HOST | USER | DEFAULT_ROLE_HOST | DEFAULT_ROLE_USER |
+------+------------+-------------------+-------------------+
| % | admin_user | % | app_owner |
| % | read_user1 | % | app_read |
| % | read_user2 | % | app_read |
| % | rw_user1 | % | app_read |
| % | rw_user1 | % | app_write |
+------+------------+-------------------+-------------------+
5 rows in set (0.06 sec)
拥有多角色的用户,在当前会话里可以进行角色互换:SET ROLE role_name;
$ mysql-u rw_user1 -p
mysql> select current_role();
+--------------------------------+
| current_role() |
+--------------------------------+
| `app_read`@`%`,`app_write`@`%` |
+--------------------------------+
1 row in set (0.05 sec)
mysql> set role app_read;
Query OK, 0 rows affected (0.05 sec)
mysql> select current_role();
+----------------+
| current_role() |
+----------------+
| `app_read`@`%` |
+----------------+
1 row in set (0.06 sec)
mysql> insert into app_db.t1(id) values(1);
ERROR 1142 (42000): INSERT command denied to user 'rw_user1'@'10.99.17.133' for table 't1'
mysql> set role app_write;
Query OK, 0 rows affected (0.05 sec)
mysql> select current_role();
+-----------------+
| current_role() |
+-----------------+
| `app_write`@`%` |
+-----------------+
1 row in set (0.05 sec)
mysql> insert into app_db.t1(id) values(1);
Query OK, 1 row affected (0.10 sec)
mandatory_roles:强制所有用户默认角色,可以通过在 mandatory_roles 系统变量的值中命名角色,可以将角色指定为强制角色 ,服务器将强制角色视为授予所有用户,因此无需明确授予任何帐户。
# 设置强制给所有用户赋予角色{app_read}
mysql> set global mandatory_roles = 'app_read';
Query OK, 0 rows affected (0.06 sec)
mysql> set global activate_all_roles_on_login = on;
Query OK, 0 rows affected (0.06 sec)
mysql> CREATE USER kuzma IDENTIFIED BY 'xxx';
Query OK, 0 rows affected (0.06 sec)
$ mysql -u kuzma -p
show grants;
+-------------------------------------------+
| Grants for kuzma@% |
+-------------------------------------------+
| GRANT USAGE ON *.* TO `kuzma`@`%` |
| GRANT SELECT ON `app_db`.* TO `kuzma`@`%` |
| GRANT `app_read`@`%` TO `kuzma`@`%` |
+-------------------------------------------+
3 rows in set (0.05 sec)
# 撤销角色,从用户上拿掉某一角色,即同时的撤销该角色拥有的权限集合
REVOKE role_name FROM user_name;
REVOKE DELETE ON db_name.* FROM role_name;
DROP ROLE role_name1, role_name2;
注意:无论是撤销,还是删除,都不能动 mandatory_roles 系统变量值中的强制角色。
没错,用户也可以是个角儿 ^_~,这是怎么回事儿呢?其实,就用户也可以当角色来用的:
# 8.0以前的MySQL GRANT语法中,用户权限授予到另一个用户上是违法的
mysql> select @@version;
+------------+
| @@version |
+------------+
| 5.7.26-log |
+------------+
1 row in set (0.06 sec)
mysql> CREATE USER user1, user2;
Query OK, 0 rows affected (0.05 sec)
mysql> GRANT user1 TO user2;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'user1 TO user2' at line 1
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 8.0.23 |
+-----------+
1 row in set (0.05 sec)
mysql> CREATE USER user1, user2;
Query OK, 0 rows affected (0.07 sec)
mysql> GRANT SELECT ON app_db.* TO user1;
Query OK, 0 rows affected (0.06 sec)
mysql> GRANT user1 TO user2;
Query OK, 0 rows affected (0.06 sec)
mysql> SHOW GTANTS FOR user2;
+-----------------------------------+
| Grants for user2@% |
+-----------------------------------+
| GRANT USAGE ON *.* TO `user2`@`%` |
| GRANT `user1`@`%` TO `user2`@`%` |
+-----------------------------------+
2 rows in set (0.05 sec)
mysql> SHOW GTANTS FOR user2 USING user1;
+-------------------------------------------+
| Grants for user2@% |
+-------------------------------------------+
| GRANT USAGE ON *.* TO `user2`@`%` |
| GRANT SELECT ON `app_db`.* TO `user2`@`%` |
| GRANT `user1`@`%` TO `user2`@`%` |
+-------------------------------------------+
3 rows in set (0.05 sec)
由此可见,用户和角色是可以互换使用的。
本文简单介绍了数据库用户和角色的权限管理应用,包括 MySQL 8.0 对角色的引入,虽然目前生产数据库暂未对角色进行更多的应用,当其实现了权限管理的多样化和精细化,可以更好地权限分离,能够满足某些特殊场景下对权限管理的需求,还是很值得期待的。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章