MySQL8新特性-Roles

一个MySQL的角色是一些权限的集合。就像一个帐号一样,可以对他进行权限的赋权和收回。
我们可以把角色授权给用户,这样帐号就拥用了角色的权限。我们可以同一个角色赋权给不同的帐号,也可以把不同的角色给同一个帐号。

CREATE ROLE and DROP ROLE enable roles to be created and removed.
GRANT and REVOKE enable privilege assignment and revocation for user accounts and roles.
SHOW GRANTS displays privilege and role assignments for user accounts and roles.
SET DEFAULT ROLE specifies which account roles are active by default.
SET ROLE changes the active roles within the current session.
The CURRENT_ROLE() function displays the active roles within the current session.
The mandatory_roles and activate_all_roles_on_login system variables enable defining mandatory roles and automatic activation of granted roles when users log in to the server.

创建一个角色:
CREATE ROLE ‘app_developer’;
给角色赋权:
GRANT ALL ON test.* TO ‘app_developer’;
把角色的权限赋给用户:
如果以前我们可以直接使用GRANT ALL ON test.* TO ‘dev1’@’localhost’ IDENTIFIED BY ‘dev1pass’;来同时建用户并赋权,但是现在我们使用下面的命令将会报错
GRANT app_developer TO ‘dev1’@’localhost’ IDENTIFIED BY ‘dev1pass’;
我们只能分开来操作:
create user ‘dev1’@’localhost’ IDENTIFIED BY ‘dev1pass’;
GRANT app_developer TO ‘dev1’@’localhost’;

这个时候mysql的role_edges表里就会多一条记录
root@mysql 03:44:38>select * from role_edges;
+———–+—————+———–+———+——————-+
| FROM_HOST | FROM_USER | TO_HOST | TO_USER | WITH_ADMIN_OPTION |
+———–+—————+———–+———+——————-+
| % | app_developer | localhost | dev1 | N |
+———–+—————+———–+———+——————-+
1 row in set (0.00 sec)

我们和以前的版本一样来查看一下用户的权限:
root@mysql 03:45:42>show grants for ‘dev1’@’localhost’;
+————————————————-+
| Grants for dev1@localhost |
+————————————————-+
| GRANT USAGE ON *.* TO `dev1`@`localhost` |
| GRANT `app_developer`@`%` TO `dev1`@`localhost` |
+————————————————-+
2 rows in set (0.00 sec)

root@mysql 03:45:53>show grants for ‘dev1’@’localhost’ using ‘app_developer’;
+——————————————————–+
| Grants for dev1@localhost |
+——————————————————–+
| GRANT USAGE ON *.* TO `dev1`@`localhost` |
| GRANT ALL PRIVILEGES ON `test`.* TO `dev1`@`localhost` |
| GRANT `app_developer`@`%` TO `dev1`@`localhost` |
+——————————————————–+
3 rows in set (0.00 sec)

这个时候我们使用dev1刚刚建的用户登一下
$mysql -udev1 -pdev1pass

dev1@(none) 04:02:33>show databases;
+——————–+
| Database |
+——————–+
| information_schema |
+——————–+
1 row in set (0.01 sec)

dev1@(none) 04:02:39>SELECT CURRENT_ROLE();
+—————-+
| CURRENT_ROLE() |
+—————-+
| NONE |
+—————-+
1 row in set (0.00 sec)

dev1@(none) 04:02:54>select * from test.a;
ERROR 1142 (42000): SELECT command denied to user ‘dev1’@’localhost’ for table ‘a’

可以发现并查不了。
这个时候我们set一下当前的角色
dev1@(none) 04:04:33>set role app_developer;
Query OK, 0 rows affected (0.00 sec)

dev1@(none) 04:04:38>SELECT CURRENT_ROLE();
+———————+
| CURRENT_ROLE() |
+———————+
| `app_developer`@`%` |
+———————+
1 row in set (0.00 sec)

dev1@(none) 04:04:42>show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| test |
+——————–+
2 rows in set (0.00 sec)

当我们set了以后可以了。
当然我们也可以SET ROLE ALL 【EXCEPT xxx】 当有多个的时候也可以这个样子
我们每次都需要这样set太累了,我们也可以直接set default
root@mysql 04:30:18>SET DEFAULT ROLE app_developer TO ‘dev1’@’localhost’;
Query OK, 0 rows affected (0.00 sec)

root@mysql 04:30:19>select * from default_roles;
+———–+——+——————-+——————-+
| HOST | USER | DEFAULT_ROLE_HOST | DEFAULT_ROLE_USER |
+———–+——+——————-+——————-+
| localhost | dev1 | % | app_developer |
+———–+——+——————-+——————-+
1 row in set (0.00 sec)

 

收回权限的时候可以使用
REVOKE role FROM user;
REVOKE privileges FROM role;

和role相关的系统参数
dba@(none) 04:50:44>show variables like ‘%role%’;
+—————————–+——-+
| Variable_name | Value |
+—————————–+——-+
| activate_all_roles_on_login | OFF |
| mandatory_roles | |
+—————————–+——-+
2 rows in set (0.00 sec)

dba@(none) 04:52:05>set global activate_all_roles_on_login=on;

https://dev.mysql.com/doc/refman/8.0/en/roles.html

MySQL8新特性-Mandatory Roles

强制角色:Mandatory roles
可以指定强制性的角色作为mandatory_roles系统变量的值。服务器将一个强制性的角色授予所有用户,所以它不需要明确授予任何帐户。
[mysqld]
mandatory_roles=’role1,role2@localhost,r3@%.example.com’
或者
SET PERSIST mandatory_roles = ‘role1,role2@localhost,r3@%.example.com’;
不过需要注意的是:
As of MySQL 8.0.4, setting mandatory_roles requires the ROLE_ADMIN privilege, in addition to the SYSTEM_VARIABLES_ADMIN or SUPER privilege normally required to set a global system variable.
Roles named in the value of mandatory_roles cannot be revoked with REVOKE or dropped with DROP ROLE or DROP USER.
SET PERSIST sets the value for the running MySQL instance. It also saves the value to be used for subsequent server restarts; see Section 13.7.5.1, “SET Syntax for Variable Assignment”. To change a value only for the running MySQL instance without saving it for subsequent restarts, use the GLOBAL keyword rather than PERSIST.

我们做一个示范:

首先建一个角色并授权:
CREATE ROLE ‘app_developer’;
GRANT ALL ON test.* TO ‘app_developer’;

然后我们把这个参数设成这个角色:
SET PERSIST mandatory_roles = ‘app_developer@%’;

然后我们创建一个用户 并不赋权
create user ‘test2’@’%’ identified by ‘test2’;
FLUSH PRIVILEGES;

我们在其它的窗口上用新加的这个帐号进去。然后可以直接set这个role
test2@information_schema 01:15:07>set role app_developer;
Query OK, 0 rows affected (0.00 sec)

也可以进行查询
test2@information_schema 01:15:15>show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| test |
+——————–+
2 rows in set (0.00 sec)

test2@information_schema 01:15:19>use test;
Database changed
test2@test 01:15:23>select * from test.a;
+——+
| id |
+——+
| 1 |
+——+
1 row in set (0.01 sec)

然后如果我们把这个参数改成空的,相应的权限也就没有了。 这个不用退出会话就会生效
test2@(none) 01:17:03>set role app_developer;
ERROR 3530 (HY000): `app_developer`@`%` is not granted to `test2`@`%`

需要注意的是 当一个角色被set了之后是不可以被删除的
dbadmin@(none) 01:20:25>drop role app_developer;
ERROR 4527 (HY000): The role `app_developer`@`%` is a mandatory role and can’t be revoked or dropped. The restriction can be lifted by excluding the role identifier from the global variable mandatory_roles.

MySQL8新特性-PERSIST

在以前是版本里我们set 一个参数的时候可以使用GLOBAL | SESSION和影响当前会话和全局的参数。但是即使是global的参数在重新启动实例以后也是会消失的。为此在MySQL8以后的版本引入了另外的两个语法参数,我们使用help set可以看到一共用了以下四个值。
[GLOBAL | SESSION | PERSIST | PERSIST_ONLY]
[@@global. | @@session. | @@persist. | @@persist_only. | @@]
简单来说PERSIST这是一个用来配置持续优化统计参数的语法。当我们set PERSIST system_var_name = expr的时候,我们可以在运行时进行配置更改并保存,在服务器重启后仍生效, 这个环境变量在修改的同时还会影响到数据文件目录的一个叫做mysqld-auto.cnf的文件,mysql在重新启动的时候,会优先使用这个文件里的参数值。mysql给我的建议是mysqld-auto.cnf文件应由管理服务器,而不是手动执行。我们先来简单的看一个例子

在修改之前我们先查看一下:
dba@(none) 10:39:24>select * from performance_schema.variables_info where VARIABLE_NAME=’mandatory_role;
+—————–+—————–+—————+———–+———–+———————+———-+———-+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH | MIN_VALUE | MAX_VALUE | SET_TIME | SET_USER | SET_HOST |
+—————–+—————–+—————+———–+———–+———————+———-+———-+
| mandatory_roles | COMPILED | | 0 | 0 | 2017-11-08 10:58:40 | | |
+—————–+—————–+—————+———–+———–+———————+———-+———-+
1 row in set (0.00 sec)

然后我们修改这个值:
SET PERSIST mandatory_roles = ‘app_developer@%’;

然后查看一下这个值的确是被修改了:
dba@(none) 10:40:43>
dba@(none) 10:40:43>select * from performance_schema.variables_info where VARIABLE_NAME=’mandatory_roles’;
+—————–+—————–+—————+———–+———–+———————+———-+———–+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH | MIN_VALUE | MAX_VALUE | SET_TIME | SET_USER | SET_HOST |
+—————–+—————–+—————+———–+———–+———————+———-+———–+
| mandatory_roles | DYNAMIC | | 0 | 0 | 2017-11-08 14:35:24 | dbadmin | localhost |
+—————–+—————–+—————+———–+———–+———————+———-+———–+
1 row in set (0.00 sec)

可以发现在我们的my.cnf文件里这个值并没有被修改。
$cat my.cnf | grep mandatory_roles

然后我们去数据文件所在的目录查看多出来的一个文件。
$cat mysqld-auto.cnf
{ “mysql_server”: {“mandatory_roles”: “app_developer@%”} }
可以看到是一个json格式的描述文件。
接下来我们重启数据库,然后查看当前参数的值。
dbadmin@(none) 10:52:49>show variables like ‘%mandatory_roles%’;
+—————–+—————–+
| Variable_name | Value |
+—————–+—————–+
| mandatory_roles | app_developer@% |
+—————–+—————–+
1 row in set (0.00 sec)

dba@(none) 10:55:11>select * from performance_schema.variables_info where VARIABLE_NAME=’mandatory_roles’\G
*************************** 1. row ***************************
VARIABLE_NAME: mandatory_roles
VARIABLE_SOURCE: PERSISTED
VARIABLE_PATH: /u01/my3306/data/mysqld-auto.cnf
MIN_VALUE: 0
MAX_VALUE: 0
SET_TIME: 2017-11-09 10:52:14
SET_USER:
SET_HOST:
1 row in set (0.00 sec)
可以发现还是修改过值。这也证明了我们的的配置进行了持久化。

那么我们怎么取消这个值设置呢。
有两种方法,它们略有一点不同
1.SET PERSIST mandatory_roles = DEFAULT;
2.RESET PERSIST IF EXISTS mandatory_roles;
在我们使用第一种方法的时候,mysqld-auto.cnf还是有这个值的,当我们再次重启的时候它还是读这个文件
$cat data/mysqld-auto.cnf
{ “mysql_server”: {“mandatory_roles”: “” } }
在我们使用第二种方法的时候就完全把这个参数的内容的去掉。
$cat data/mysqld-auto.cnf
{ “mysql_server”: { } }

使用第二种如果不存在的话:
dba@(none) 10:59:27>RESET PERSIST IF EXISTS mandatory_roles;
Query OK, 0 rows affected, 1 warning (0.00 sec)

dba@(none) 11:01:22>show warnings;
+———+——+——————————————————————+
| Level | Code | Message |
+———+——+——————————————————————+
| Warning | 3615 | Variable mandatory_roles does not exist in persisted config file |
+———+——+——————————————————————+
1 row in set (0.00 sec)

dba@(none) 11:01:27>RESET PERSIST mandatory_roles;
ERROR 3615 (HY000): Variable mandatory_roles does not exist in persisted config file

当然我们也可以只使用@@persist_only 来影响mysqld-auto.cnf的文件,在下次重启以后才生产。

整个的使用就像oralce的pfile和spfile。

如果你不想让mysqld-auto.cnf中的配置生效,可以在启动时关闭只读参数persisted_globals_load,这样在启动时就不会载入mysqld-auto.cnf中的配置项了

https://dev.mysql.com/doc/refman/8.0/en/set-variable.html?spm=5176.100239.blogcont60656.10.SVzv1S