MySQL5.7中的角色如何使用

关注我《程序猿集锦》获取更多分享。


  • 角色概念
  • SQL集合
  • 探索过程
  • 创建角色
  • 安装mysql_no_login插件
  • 验证创建的角色
  • 创建用户
  • 修改密码策略
  • 把角色赋予用户
  • 验证用户权限
  • 启用角色代理功能
  • 再次验证用户权限
  • 确定是否为代理用户
  • 注意的问题
  • 在角色中新增账号
  • 应用举例
  • 总结

角色概念

MySQL5.7版本中开始支持角色的功能,但这并不是像MySQL8.0版本中的role的概念一样。在8.0版本中,有create role的语法,但是在5.7版本中并没有这样的语法。在5.7版本所谓的角色是使用create user语法来创建的,它更像是一种代理的概念。

SQL集合

下面是实验中使用到的SQL语句

/* 创建数据库 mydb1 */drop database if exists mydb1;create database mydb1 default charset utf8mb4;/* 创建表 mytab1 */use mydb1;drop table if exists mytab1;create table mytab1(id smallint not null primary key auto_increment,  col1 varchar(255),  col2 varchar(255),  col3 varchar(255));/* 初始化数据 mytab1 */insert into mytab1(col1,col2,col3) values('a1','a2','a3'),('b1','b2','b3'),('c1','c2','c3');/* 创建角色myrole1 并为角色授权 */drop user if exists 'myrole1'@'%';create user 'myrole1'@'%';grant select on mydb1.* to 'myrole1'@'%';/* 创建用户myuser1 并把角色myrole1赋予该用户 */drop user if exists 'myuser1'@'%';create user 'myuser1'@'%' identified by 'myuser1';grant proxy on 'myrole1'@'%' to 'myuser1'@'%';/* 创建用户myuser2 并把角色myrole1赋予该用户 */drop user if exists 'myuser2'@'%';create user 'myuser2'@'%' identified by 'myuser2';grant proxy on 'myrole1'@'%' to 'myuser2'@'%';/* 创建数据库 mydb2 */drop database if exists mydb2;create database mydb2 default charset utf8mb4;/* 创建表 mytab2 */use mydb2;drop table if exists mytab2;create table mytab2(id smallint not null primary key auto_increment,  col1 varchar(255),  col2 varchar(255),  col3 varchar(255));/* 初始化数据 mytab2 */insert into mytab2(col1,col2,col3) values('a1','a2','a3'),('b1','b2','b3'),('c1','c2','c3');

探索过程

创建角色

在创建角色的时候可能有如下提示,是因为MySQL服务器设置的密码策略不允许创建没有密码的用户,但是我们的角色确实不需要使用密码的,因为它不需要登录。

mysql> create user 'myrole1'@'%';ERROR 1819 (HY000): Your password does not satisfy the current policy requirementsmysql>

那么我们可以这样创建用户,但是又遇到了插件没有安装的错误提示:

mysql> create user 'myrole1'@'%' identified with mysql_no_login;ERROR 1524 (HY000): Plugin 'mysql_no_login' is not loadedmysql>

因为角色不需要登录,我们可以有以下三种方式不让创建的角色登录,这里我们选在第一种方式。

  • 创建用户的时候指定mysql_no_login属性。
  • 创建用户的时候,把它给设置为locked,一个拥有密码,但是是锁定状态的用户,既可把它当做一个角色来用。
  • 创建用户的时候,把它的密码设置为一个特别复杂的密码,自己也不用记住,别人也会记住。这样它也可以为角色来用。

安装mysql_no_login插件

那么就安装这个缺失的插件,在安装之前,先检查一下插件的情况:

mysql> show plugins;+----------------------------+----------+--------------------+----------------------+---------+| Name                       | Status   | Type               | Library              | License |+----------------------------+----------+--------------------+----------------------+---------+| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     || sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     || CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     || partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     || validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     |+----------------------------+----------+--------------------+----------------------+---------+45 rows in set (0.01 sec)mysql>

发现确实没有安装前面错误信息中提示的mysql_no_login插件,执行下面的命令安装该插件

mysql> install plugin mysql_no_login soname 'mysql_no_login.so';Query OK, 0 rows affected (0.01 sec)mysql>

再次查看安装的plugin是否有mysql_no_login插件。

mysql> show plugins;+----------------------------+----------+--------------------+----------------------+---------+| Name                       | Status   | Type               | Library              | License |+----------------------------+----------+--------------------+----------------------+---------+| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     || sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     || CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     || MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     || partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     || ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     || validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     || mysql_no_login             | ACTIVE   | AUTHENTICATION     | mysql_no_login.so    | GPL     |+----------------------------+----------+--------------------+----------------------+---------+46 rows in set (0.00 sec)mysql>

关于更多关于MySQL中插件的安装与卸载的问题,请参考MySQL官方文档:Installing and Uninstalling Plugins

接着我们创建我们的角色

mysql> create user 'myrole1'@'%' identified with mysql_no_login;Query OK, 0 rows affected (0.02 sec)mysql> 

验证创建的角色

创建完成后,我们去mysql.user表中查询,发现已经存在我们创建的角色了,并且我们创建的角色它的plugin选项显示不能登录,密码也是空的。

mysql> select user, host, plugin, authentication_string from mysql.user;+---------------+-----------+-----------------------+-------------------------------------------+| user          | host      | plugin                | authentication_string                     |+---------------+-----------+-----------------------+-------------------------------------------+| root          | %         | mysql_native_password | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B || mysql.session | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || mysql.sys     | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || myrole1       | %         | mysql_no_login        |                                           |+---------------+-----------+-----------------------+-------------------------------------------+4 rows in set (0.00 sec)mysql>

创建用户

下面我们创建用户,用户名和密码我们设置为相同的字符串myuser1

mysql> create user 'myuser1'@'%' identified by 'myuser1';ERROR 1819 (HY000): Your password does not satisfy the current policy requirementsmysql> SHOW VARIABLES LIKE 'validate_password%';+--------------------------------------+--------+| Variable_name                        | Value  |+--------------------------------------+--------+| validate_password_check_user_name    | OFF    || validate_password_dictionary_file    |        || validate_password_length             | 8      || validate_password_mixed_case_count   | 1      || validate_password_number_count       | 1      || validate_password_policy             | MEDIUM || validate_password_special_char_count | 1      |+--------------------------------------+--------+7 rows in set (0.03 sec)mysql>

修改密码策略

发现创建用户失败,因为我们给用户指定的密码太简单了,需要设置一个复杂的密码。这是因为我们的这个MySQL服务安装了密码插件,就是前面我们看到的validate_password插件。它要求用户的密码必须满足一定的条件才可以创建成功。为了方便,我们暂时把这个密码的验证的等级修改为low低等级的,密码的长度验证修改为1。如果你的MySQL没有安装或没有启用validate_password插件,那么你的MySQL就可以不用做下面的设置,直接创建对应的用户就可以了。

mysql> set global validate_password_policy=low;Query OK, 0 rows affected (0.01 sec)mysql> set global validate_password_length=1;Query OK, 0 rows affected (0.01 sec)mysql> SHOW VARIABLES LIKE 'validate_password%';+--------------------------------------+-------+| Variable_name                        | Value |+--------------------------------------+-------+| validate_password_check_user_name    | OFF   || validate_password_dictionary_file    |       || validate_password_length             | 4     || validate_password_mixed_case_count   | 1     || validate_password_number_count       | 1     || validate_password_policy             | LOW   || validate_password_special_char_count | 1     |+--------------------------------------+-------+7 rows in set (0.00 sec)mysql>

然后在创建用户,并检查创建后的用户是否成功。可以看到我们创建的新的用户myuser1是可以登录,并且有密码的。

mysql> create user 'myuser1'@'%' identified by 'myuser1';Query OK, 0 rows affected (0.01 sec)mysql> select user, host, plugin, authentication_string from mysql.user;+---------------+-----------+-----------------------+-------------------------------------------+| user          | host      | plugin                | authentication_string                     |+---------------+-----------+-----------------------+-------------------------------------------+| root          | %         | mysql_native_password | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B || mysql.session | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || mysql.sys     | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || myrole1       | %         | mysql_no_login        |                                           || myuser1       | %         | mysql_native_password | *A8866F07643159AF3EDB07E8D0F951C740E7014F |+---------------+-----------+-----------------------+-------------------------------------------+5 rows in set (0.00 sec)mysql>

把角色赋予用户

上面我们把角色和用户都准备好了,下面我们把角色赋予创建好的用户,让这个用户具有这个角色。

mysql> grant proxy on 'myrole1'@'%' to 'myuser1'@'%';Query OK, 0 rows affected (0.02 sec)mysql> show grants for myuser1;+-----------------------------------------------+| Grants for myuser1@%                          |+-----------------------------------------------+| GRANT USAGE ON *.* TO 'myuser1'@'%'           || GRANT PROXY ON 'myrole1'@'%' TO 'myuser1'@'%' |+-----------------------------------------------+2 rows in set (0.00 sec)mysql> show grants for myrole1;+--------------------------------------------+| Grants for myrole1@%                       |+--------------------------------------------+| GRANT USAGE ON *.* TO 'myrole1'@'%'        || GRANT SELECT ON `mydb1`.* TO 'myrole1'@'%' |+--------------------------------------------+2 rows in set (0.00 sec)mysql> select host, user, proxied_host, proxied_user, with_grant, grantor from mysql.proxies_priv;+------+---------+--------------+--------------+------------+----------------------+| host | user    | proxied_host | proxied_user | with_grant | grantor              |+------+---------+--------------+--------------+------------+----------------------+| %    | root    |              |              |          1 | boot@connecting host || %    | myuser1 | %            | myrole1      |          0 | root@172.18.0.1      |+------+---------+--------------+--------------+------------+----------------------+2 rows in set (0.00 sec)mysql>

验证用户权限

此时我们已经把角色赋予对应的用户了,但是我们发现我们使用用户myuser1登录后,并不能看到我们希望它看到的数据库。

(base) ➜  ~ mysql -umyuser1 -pmyuser1 -h127.0.0.1 -P33061mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema |+--------------------+1 row in set (0.05 sec)mysql> use mydb1;ERROR 1044 (42000): Access denied for user 'myuser1'@'%' to database 'mydb1'mysql> exit;

启用角色代理功能

这是因为要启用角色代理功能,还需要配置两个参数,需要设置如下两个参数的值为ON才可以。

mysql> show global variables like 'check_proxy_users'; /*此时是OFF*/+-------------------+-------+| Variable_name     | Value |+-------------------+-------+| check_proxy_users | OFF   |+-------------------+-------+1 row in set (0.01 sec)mysql> show global variables like 'mysql_native_password_proxy_users';  /*此时是OFF*/+-----------------------------------+-------+| Variable_name                     | Value |+-----------------------------------+-------+| mysql_native_password_proxy_users | OFF   |+-----------------------------------+-------+1 row in set (0.01 sec)mysql> set global check_proxy_users=ON;  /*设置为ON*/Query OK, 0 rows affected (0.01 sec)mysql> set global mysql_native_password_proxy_users=ON;  /*设置为ON*/Query OK, 0 rows affected (0.01 sec)mysql> show global variables like 'check_proxy_users';  /*检查结果是否为ON*/+-------------------+-------+| Variable_name     | Value |+-------------------+-------+| check_proxy_users | ON    |+-------------------+-------+1 row in set (0.01 sec)mysql> show global variables like 'mysql_native_password_proxy_users';  /*检查结果是否为ON*/+-----------------------------------+-------+| Variable_name                     | Value |+-----------------------------------+-------+| mysql_native_password_proxy_users | ON    |+-----------------------------------+-------+1 row in set (0.01 sec)mysql>

上面的设置只是暂时生效,如果要永久生效,请把上面的参数配置在MySQL的参数配置文件中my.cnf中,这样MySQL在重启后,仍然会启用角色代理的功能。配置内容如下:

[mysqld]check_proxy_users=ONmysql_native_password_proxy_users=ON

再次验证用户权限

此时再次验证myuser1是否可以看到mydb1这个数据库。通过下面的示例可以看到,已经可以查询mydb1下面的表了。

(base) ➜  ~ mysql -umyuser1 -pmyuser1 -h127.0.0.1 -P33061mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema || mydb1              |+--------------------+2 rows in set (0.03 sec)mysql> use mydb1;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> show tables;+-----------------+| Tables_in_mydb1 |+-----------------+| mytab1          |+-----------------+1 row in set (0.01 sec)mysql> select * from mytab1;+----+------+------+------+| id | col1 | col2 | col3 |+----+------+------+------+|  1 | a1   | a2   | a3   ||  2 | b1   | b2   | b3   ||  3 | c1   | c2   | c3   |+----+------+------+------+3 rows in set (0.01 sec)mysql>

确定是否为代理用户

当使用代理用户访问MySQL的时候,可以看到如下的区别,函数CURRENT_USER()返回值并不是当前登录的myuser1,而是角色myrole1

mysql> SELECT USER(), CURRENT_USER();+--------------------+----------------+| USER()             | CURRENT_USER() |+--------------------+----------------+| myuser1@172.18.0.1 | myrole1@%      |+--------------------+----------------+1 row in set (0.00 sec)mysql>

查看当前登录的用户是否使用代理角色登录,可以使用下面的这个SQL语句查看。

mysql> SELECT @@proxy_user;+---------------+| @@proxy_user  |+---------------+| 'myuser1'@'%' |+---------------+1 row in set (0.00 sec)mysql> show variables like 'proxy_user';+---------------+---------------+| Variable_name | Value         |+---------------+---------------+| proxy_user    | 'myuser1'@'%' |+---------------+---------------+1 row in set (0.01 sec)mysql>

如果是一个非代理用户登录的数据库,参数proxy_user的查看的结果为空NULL,如下所示:

mysql> SELECT @@proxy_user;+--------------+| @@proxy_user |+--------------+| NULL         |+--------------+1 row in set (0.00 sec)mysql> show variables like 'proxy_user';+---------------+-------+| Variable_name | Value |+---------------+-------+| proxy_user    |       |+---------------+-------+1 row in set (0.09 sec)mysql>

注意的问题

上面的myuser1已经具有了myrole1这个角色,当我们使用myuser1登录数据库后,可以拥有myrole1这个角色所拥有的权限。但是如果此时,我们单独给myuser1授予一个新的权限,这个权限是和myrole1角色所拥有的权限是相互独立的,也就是说myuser1这个用户,除了具有myrole1这个角色之外,它还有属于自己的一些权限,那么此时用myuser1登录到数据库之后,是看不到它自己特有的那部分权限的。

另外,如果授予一个用户两个角色,则使用该用户登录的时候,只会使用第一个授予的角色登录。如下所示:myuser1出来具有myrole1这个角色之外,还有yourrole1这个角色。而myrole1mydb开头的数据库有读权限,yourrole1yourdb开头的数据库有读权限。而此时我们使用myuser1登录数据库之后,发现只能看到myrole1角色所能看到的内容,看不到它的第另外一个角色yourrole1所能看到数据库。

/* 下面命令都使用root用进行查看 */mysql> select host, user, proxied_host, proxied_user, with_grant, grantor from mysql.proxies_priv;+------+---------+--------------+--------------+------------+----------------------+| host | user    | proxied_host | proxied_user | with_grant | grantor              |+------+---------+--------------+--------------+------------+----------------------+| %    | root    |              |              |          1 | boot@connecting host || %    | myuser1 | %            | myrole1      |          0 | root@172.18.0.1      || %    | myuser1 | %            | yourrole1    |          0 | root@172.18.0.1      |+------+---------+--------------+--------------+------------+----------------------+4 rows in set (0.01 sec)mysql> show grants for 'myrole1'@'%';+--------------------------------------------+| Grants for myrole1@%                       |+--------------------------------------------+| GRANT USAGE ON *.* TO 'myrole1'@'%'        || GRANT SELECT ON `mydb%`.* TO 'myrole1'@'%' |+--------------------------------------------+2 rows in set (0.00 sec)mysql> show grants for 'yourrole1'@'%';+------------------------------------------------+| Grants for yourrole1@%                         |+------------------------------------------------+| GRANT USAGE ON *.* TO 'yourrole1'@'%'          || GRANT SELECT ON `yourdb%`.* TO 'yourrole1'@'%' |+------------------------------------------------+2 rows in set (0.00 sec)mysql> show grants for 'myuser1'@'%';+-------------------------------------------------+| Grants for myuser1@%                            |+-------------------------------------------------+| GRANT USAGE ON *.* TO 'myuser1'@'%'             || GRANT SELECT ON `herdb`.* TO 'myuser1'@'%'      || GRANT PROXY ON 'myrole1'@'%' TO 'myuser1'@'%'   || GRANT PROXY ON 'yourrole1'@'%' TO 'myuser1'@'%' |+-------------------------------------------------+4 rows in set (0.00 sec)mysql> show databases;+-------------------------+| Database                |+-------------------------+| information_schema      || docker_compose_instance || herdb                   || mydb1                   || mydb2                   || mydb3                   || mysql                   || performance_schema      || sys                     || yourdb1                 || yourdb2                 |+-------------------------+11 rows in set (0.00 sec)mysql>

myuser1等到数据库进行验证,看它能看到哪个角色锁能看到的数据库。通过验证发现,只能看到myrole1这个角色能看到的数据库,它自己单独被授权的herdb和它的另外一个角色yourrole1能看到的yourdb开头的数据库都看不到。这是因为myuser1在登录的时候,就被判定为是使用myrole1角色登录的,它只能拥有myrole1这个角色所具有的权限,其他的权限myuser1则没有。

(base) ➜  ~ mysql -umyuser1 -pmyuser1 -h127.0.0.1 -P33061mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema || mydb1              || mydb2              || mydb3              |+--------------------+4 rows in set (0.00 sec)mysql> select user(), current_user();+--------------------+----------------+| user()             | current_user() |+--------------------+----------------+| myuser1@172.18.0.1 | myrole1@%      |+--------------------+----------------+1 row in set (0.00 sec)mysql>

总结为:如果一个用户被赋予了某一个角色,则它只能使用这个角色的身份进行登录,登录后也只能使用这个角色所有的权限,自己独有的或者额外赋予的其他权限,登录后不能使用。同时,一个用户不建议赋予2个及2个以上的角色。因为MySQL不会取两个角色对应权限的并集作为用户最后的权限,只会取第一个角色的权限。

在角色中新增账号

我们再次创建一个用户myuser2,然后把myrole1这个角色也赋予myuser2,看下myuser2是不是和myuser1拥有同样的权限。

mysql> drop user if exists 'myuser2'@'%';Query OK, 0 rows affected, 1 warning (0.01 sec)mysql> create user 'myuser2'@'%' identified by 'myuser2';Query OK, 0 rows affected (0.01 sec)mysql> grant proxy on 'myrole1'@'%' to 'myuser2'@'%';Query OK, 0 rows affected (0.02 sec)mysql> show grants for 'myuser2'@'%';+-----------------------------------------------+| Grants for 'myuser2'@'%'                      |+-----------------------------------------------+| GRANT USAGE ON *.* TO 'myuser2'@'%'           || GRANT PROXY ON 'myrole1'@'%' TO 'myuser2'@'%' |+-----------------------------------------------+2 rows in set (0.00 sec)mysql> select user, host, plugin, authentication_string from mysql.user;+---------------+-----------+-----------------------+-------------------------------------------+| user          | host      | plugin                | authentication_string                     |+---------------+-----------+-----------------------+-------------------------------------------+| root          | %         | mysql_native_password | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B || mysql.session | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || mysql.sys     | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE || myrole1       | %         | mysql_no_login        |                                           || myuser1       | %         | mysql_native_password | *A8866F07643159AF3EDB07E8D0F951C740E7014F || myuser2       | %         | mysql_native_password | *05BB3827F42B15D8C38C720FBBDACE970076AF83 |+---------------+-----------+-----------------------+-------------------------------------------+6 rows in set (0.00 sec)mysql> select host, user, proxied_host, proxied_user, with_grant, grantor from mysql.proxies_priv;+------+---------+--------------+--------------+------------+----------------------+| host | user    | proxied_host | proxied_user | with_grant | grantor              |+------+---------+--------------+--------------+------------+----------------------+| %    | root    |              |              |          1 | boot@connecting host || %    | myuser1 | %            | myrole1      |          0 | root@172.18.0.1      || %    | myuser2 | %            | myrole1      |          0 | root@172.18.0.1      |+------+---------+--------------+--------------+------------+----------------------+3 rows in set (0.01 sec)mysql>

使用myuser2登录进行验证,通过下面的登录验证,我们发现myuser2也拥有了和myuser1相同的权限。

(base) ➜  ~ mysql -umyuser2 -pmyuser2 -h127.0.0.1 -P33061mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema || mydb1              |+--------------------+2 rows in set (0.01 sec)mysql> use mydb1;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> show tables;+-----------------+| Tables_in_mydb1 |+-----------------+| mytab1          |+-----------------+1 row in set (0.00 sec)mysql> select * from mytab1;+----+------+------+------+| id | col1 | col2 | col3 |+----+------+------+------+|  1 | a1   | a2   | a3   ||  2 | b1   | b2   | b3   ||  3 | c1   | c2   | c3   |+----+------+------+------+3 rows in set (0.00 sec)mysql> select user(), current_user();+--------------------+----------------+| user()             | current_user() |+--------------------+----------------+| myuser2@172.18.0.1 | myrole1@%      |+--------------------+----------------+1 row in set (0.01 sec)mysql> show variables like 'proxy_user';+---------------+---------------+| Variable_name | Value         |+---------------+---------------+| proxy_user    | 'myuser2'@'%' |+---------------+---------------+1 row in set (0.24 sec)mysql>

应用举例

在多租户的场景下面,一个租户一个schema,这些schema共同存在于一个MySQL数据库实例中,但是schema的名称有某规律:比如是以指定的字符串开头,后面跟上不同的租户的名称。

例如下面这样的数据库,都已mydb开头,用1、2、3来表示不同的租户,当然这里的1、2、3可以使用有意义的字符来标识。这里我们只是拿1、2、3来举例说明。

mysql> show databases like 'mydb%';+------------------+| Database (mydb%) |+------------------+| mydb1            || mydb2            || mydb3            |+------------------+3 rows in set (0.00 sec)mysql>

此时如果需要让测试组中所有的测试人员,对mydb开头的数据库都有查询的权限,该如何实现?我们可以针对不同测试人员分别给他们授予读的权限,例如下面这样:

grant select on mydb1.* to 'myuser1'@'%';grant select on mydb2.* to 'myuser1'@'%';grant select on mydb3.* to 'myuser1'@'%';/*或者使用下面这一句授权语句来替代上面的三句*/grant select on `mydb%`.* to 'myuser1'@'%';

除了上面的方式之外,结合前面我介绍的角色的概念,我们很容易想到使用角色来解决。

我们可以把所有对mydb开头的数据库的查询权限都赋予一个角色myrole1,然后把这个角色赋予所有测试人员,让所有的测试人员的账号都使用这个角色代理登录到MySQL数据库,这样就可以了。示例如下:

grant select on `mydb%`.* to 'myrole1'@'%';  /*此时,角色myrole1对所有mydb开头的数据库都有查询的权限了*//*以后人只要新增加一个账号,就把这个角色赋予对应新增加的账号即可*/create user 'myuser2'@'%' identified by 'myuser2';  /*新增加myuser2用户*/grant proxy on 'myrole1'@'%' to 'myuser2'@'%';  /*此时新增的用户myuser2对所有mydb开头的数据库都有查询权限了*/create user 'myuser3'@'%' identified by 'myuser3';  /*新增加myuser3用户*/grant proxy on 'myrole1'@'%' to 'myuser3'@'%'; /*此时新增的用户myuser3对所有mydb开头的数据库都有查询权限了*/

总结

要求使用MySQL5.7中的角色功能,我们需要如下几步:

  • 确认数据库在参数配置上,启用了check_proxy_users=onmysql_native_password_proxy_users=0的配置。如果你的密码插件采用的是sha256_password则需要启用sha256_password_proxy_users=on而不是mysql_native_password_proxy_users=on。但是一般MySQL5.7中密码插件默认都是使用的mysql_native_password
  • 创建有一个不具有密码的用户,这个用户就是我们后面要使用的角色。当然如果数据库安装并启用了密码复杂度插件,此时的数据库是不允许创建一个不带密码的用户,这里也可以创建一个具有密码但是处于lock状态的用户来作为角色使用,创建该用户的时候就把它给锁定上,不让其可以正常登录。
  • 为这个角色赋予它需要的权限,就把这个角色当成一个正常的用户一样来授权就行。
  • 创建一个正常的拥有密码的用户,把前面创建的角色赋予这个新创建的用户。
  • 使用新创建的用户去登录验证一下是否可以访问到它所拥有的角色对应的权限。
  • 一个用户不能具有两个角色。已经被赋予某一个角色的用户也不能再次对它进行单独授权。用户登录后的权限不能取各个角色的并集,这是算是MySQL5.7版本中角色的一个缺点。

关注我《程序猿集锦》获取更多分享。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章