MySQL 的权限和账户管理

1. 实验介绍

1.1 实验内容

本节实验我们将带领大家学习 MySQL 的访问控制及用户的管理。

1.2 实验知识点

  • MySQL 的权限
  • 账户管理
  • 授权管理

2. 访问权限

MySQL 有自己的权限管理系统,而服务器将访问控制相关的权限信息存储在数据库中。在服务器启动时,将会读取这些表的内容,并且基于表中的内容进行访问控制。下面我们将简单介绍这些表的内容。

2.1 概述

关于账户权限的信息被存储在系统数据库 mysql 的 user, db, tables_priv, columns_priv 以及 procs_priv 表中。

包含的相关信息如下:

  • user 用户账户,全局权限和其它非特权列
  • db 数据库级别的特权
  • tables_priv 表级特权
  • columns_priv 列级特权
  • procs_priv 存储过程和函数权限

2.2 user

对于 MySQL 用户来说,账户相关的信息被存储在 mysql 数据中的数据表 user 中:

# 我们可以查看 USER 表的列信息
mysql> desc mysql.user;
+------------------------+-----------------------------------+------+-----+---------+-------+
| Field                  | Type                              | Null | Key | Default | Extra |
+------------------------+-----------------------------------+------+-----+---------+-------+
| Host                   | char(60)                          | NO   | PRI |         |       |
| User                   | char(16)                          | NO   | PRI |         |       |
| Password               | char(41)                          | NO   |     |         |       |
| Select_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Insert_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Update_priv            | enum('N','Y')                     | NO   |     | N       |       |
...

从表中可以知道 user 表是由 Host 和 User 项一起作为主键的,即在 MySQL 中,主机名和用户名一起作为标识来识别用户。

在第一节内容中,讲述了如何连接到 MySQL 服务器,而在对服务器进行访问时,会有一个连接验证的阶段。这个的验证阶段就需要主机名,用户名以及密码等内容进行验证。

这里需要特别强调,主机名和用户名一起作为标识。例如有一台服务器,这时我们有两个客户端分别为 A 和 B。两个客户端都使用用户名为 shiyanlou 的用户登陆,但是由于它们是不同的客户端主机,即使两者使用的用户名相同,它们在连接到服务器端时会被当作两个不同的用户

表中的 Select_priv,Insert_priv,Update_priv等代表该用户是否拥有全局相应操作的特权(privilege),缩写为 priv,即查询,插入,更新的特权。

然后我们查看用户表 mysql.user 的部分信息,如下所示:

mysql> select host,user,password,select_priv from mysql.user;
+-----------+------------------+-------------------------------------------+-------------+
| host      | user             | password                                  | select_priv |
+-----------+------------------+-------------------------------------------+-------------+
| localhost | root             |                                           | Y           |
| ubuntu    | root             |                                           | Y           |
| 127.0.0.1 | root             |                                           | Y           |
| ::1       | root             |                                           | Y           |
| localhost | debian-sys-maint | *C6B4BF1D2B688BB0C6DFBD20FD5457C4D583D3A1 | Y           |
+-----------+------------------+-------------------------------------------+-------------+

可以看到此时系统中的用户都为 root 用户,拥有全局的查询特权。

2.3 db

而除了全局特权之外,我们还可以指定数据库级别的特权,如下所示:

mysql> desc mysql.db;
+-----------------------+---------------+------+-----+---------+-------+
| Field                 | Type          | Null | Key | Default | Extra |
+-----------------------+---------------+------+-----+---------+-------+
| Host                  | char(60)      | NO   | PRI |         |       |
| Db                    | char(64)      | NO   | PRI |         |       |
| User                  | char(16)      | NO   | PRI |         |       |
| Select_priv           | enum('N','Y') | NO   |     | N       |       |
| Insert_priv           | enum('N','Y') | NO   |     | N       |       |
| Update_priv           | enum('N','Y') | NO   |     | N       |       |
| Delete_priv           | enum('N','Y') | NO   |     | N       |       |
| Create_priv           | enum('N','Y') | NO   |     | N       |       |
...

对于 mysql.db 表来说,Host, Db, User 三者作为表的主键,描述的是用户与数据库的权限。

即用户是否具有对该数据库进行查找,插入,删除等操作的特权。

2.4 表和列

由于各个表所描述的权限所处的层级不一样,因此一些具体的操作权限也会有区别。因为在上面的内容中,我们并未列出表中的全部字段,所以看不到这一区别。

除了在全局和数据库级别上进行访问权限的限制之外,MySQL 中还提供表级和列级的权限控制,如下所示,分别为 tables_priv 和 colums_priv 的列:

mysql> desc mysql.tables_priv;

mysql> desc mysql.columns_priv;

3. 账户管理

在上面的内容中,我们描述了访问权限的一些知识,在本节内容中,我们将介绍关于用户的一些知识,并结合上面的权限,带领大家学习用户授权的相关知识。

3.1 root 用户

在实验楼的在线实验环境中,我们并未对 root 用户设置相应的密码,例如刚刚我们查询的 mysql.user 表的信息:

mysql> select Host,User,Password from mysql.user;
+-----------+------------------+-------------------------------------------+
| Host      | User             | Password                                  |
+-----------+------------------+-------------------------------------------+
| localhost | root             |                                           |
| ubuntu    | root             |                                           |
| 127.0.0.1 | root             |                                           |
| ::1       | root             |                                           |
| localhost | debian-sys-maint | *C6B4BF1D2B688BB0C6DFBD20FD5457C4D583D3A1 |
+-----------+------------------+-------------------------------------------+

如上图所示,前四个用户为 MySQL 创建的 root 用户,并且 localhost,ubuntu,127.0.0.1和 IPV6 格式的 ::1 都是指向的同一个地址。它们的密码一栏都为空,因为实验环境中并未设置 root 用户的密码。

这里之所以会创建四个用户,是由于实验环境中的 MySQL 版本为 5.5 。而在 5.7 中只会创建一个 root@localhost 的用户。

而最后一个 debian-sys-maint 则为 ubuntu 系统创建的用户,为了方便管理 MySQL 服务在 Ubuntu 中的运行。

除此之外,还可能存在匿名账户,在实验环境中并不存在。

对于没有设置密码的用户,我们使用其连接 MySQL 服务时,不需要使用 -p 参数,如下所示:

shiyanlou:~/ $ mysql -u root                                         [15:21:10]
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 71
Server version: 5.5.50-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

3.2 创建账户

创建账户,一般有两种方式:

  • 使用 MySQL 提供的 CREATE USER 和 GRANT 等语句。(推荐使用的方式)
  • 通过修改 mysql.user 表创建账户。

CREATE USER 对于创建用户的详细语法较为复杂,这里没有全部列举。

CREATE USER [IF NOT EXISTS]
    user IDENTIFIED BY 'password';

user 为账户名称,合法的语法为 'user_name'@'host_name',例如 root@localhost

如下所示,我们创建一个名为 syl001@localhost 的账户,密码为 shiyanlou:

mysql> CREATE USER syl001@localhost IDENTIFIED BY "shiyanlou";
Query OK, 0 rows affected (0.26 sec)

查询 mysql.user 表,查看 syl001 用户:

mysql> SELECT Host,User,Password FROM mysql.user;
+-----------+------------------+-------------------------------------------+
| Host      | User             | Password                                  |
+-----------+------------------+-------------------------------------------+
| localhost | root             |                                           |
| ubuntu    | root             |                                           |
| 127.0.0.1 | root             |                                           |
| ::1       | root             |                                           |
| localhost | debian-sys-maint | *C6B4BF1D2B688BB0C6DFBD20FD5457C4D583D3A1 |
| localhost | syl001           | *FFB8814DBE01A23A0780B2DFF96C426CA67A9752 |
+-----------+------------------+-------------------------------------------+
6 rows in set (0.00 sec)

直接修改 mysql.user 表 如下所示,我们直接使用 mysql.user 表进行操作,插入一条数据:

mysql> INSERT into mysql.user(Host, User, Password) values ("localhost", "syl002", "shiyanlou");

mysql> SELECT Host,User,Password FROM mysql.user;
+-----------+------------------+-------------------------------------------+
| Host      | User             | Password                                  |
+-----------+------------------+-------------------------------------------+
| localhost | root             |                                           |
| ubuntu    | root             |                                           |
| 127.0.0.1 | root             |                                           |
| ::1       | root             |                                           |
| localhost | debian-sys-maint | *C6B4BF1D2B688BB0C6DFBD20FD5457C4D583D3A1 |
| localhost | syl001           | *FFB8814DBE01A23A0780B2DFF96C426CA67A9752 |
| localhost | syl002           | shiyanlou                                 |
+-----------+------------------+-------------------------------------------+
7 rows in set (0.00 sec)

如上所示,可以看到 syl002 用户添加成功,但是 password 字段显示的是由我们指定的密码 shiyanlou ,不过这样插入的用户数据并不合法,因为密码字段并没有经过 MySQL 相应的处理,所以使用 shiyanlou 这个密码和用户名并不能进行合法登录。

3.3 删除用户

删除用户的语法为:

DROP USER [IF EXISTS] user [, user] ...

例如,删除刚刚创建的 syl002@localhost 账户:

mysql> DROP USER "syl002"@"localhost";
Query OK, 0 rows affected (0.00 sec)

此时,再次查看 mysql.user 表,可以发现 syl002@localhost 已经被删除。

3.4 修改密码

修改用户的密码,由于版本的差异,在 5.7.6 之后,需要使用如下语法:

ALTER USER user IDENTIFIED BY 'new_password';

在 5.7.6 之前,即实验环境中,使用:

SET PASSWORD FOR user = PASSWORD('new_password');

如下所示,我们为 root 用户设置密码为 123456:

mysql> SET PASSWORD FOR "root"@"localhost" = PASSWORD("123456");
Query OK, 0 rows affected (0.00 sec)

这时,我们再次查询 mysql.user 表的数据:

mysql> SELECT Host,User,Password FROM mysql.user;
+-----------+------------------+-------------------------------------------+
| Host      | User             | Password                                  |
+-----------+------------------+-------------------------------------------+
| localhost | root             | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| ubuntu    | root             |                                           |
| 127.0.0.1 | root             |                                           |
| ::1       | root             |                                           |
| localhost | debian-sys-maint | *C6B4BF1D2B688BB0C6DFBD20FD5457C4D583D3A1 |
| localhost | syl001           | *FFB8814DBE01A23A0780B2DFF96C426CA67A9752 |
+-----------+------------------+-------------------------------------------+

需要说明的是,如果在安装 MySQL 的时候分配了 root 密码,那么前四个由 MySQL 创建的用户的密码就会是一样的。

4. 授权

在 MySQL 中,我们经常会接触到的有关权限的语句: GRANT 和 REVOKE,它们分别为用户授权和撤销授权。

而在 GRANT 语句中指定的账户不存在时,GRANT 会隐式的创建它。

授权的语法大致如下:

GRANT priv_type [(column_list)]
      [, priv_type [(column_list)]] ...
    ON priv_level
    TO user IDENTIFIED BY 'password'] ...

priv_level: {
   *.*
  | db_name.*
  | db_name.tbl_name
  | tbl_name
  | db_name.routine_name
}

priv_type 代表的是特权权限,部分内容如下图所示,

ALL 代表所有的权限,其它权限都对应着 mysql 数据库的 user,db 等表中的内容。而可选的 [(column_list)] 用于定义了列级权限时使用。

priv_level 代表的是特权级,具体含义如下所示:

  • *.* 代表全局,即所有的数据库以及数据库中所有的内容
  • db_name.* 代表数据库,即数据库所有的内容
  • db_name.tbl_name 即数据库中指定的表
  • tbl_name 未指定数据库,为默认数据库中的表
  • db_name.routine_name 存储过程的权限(未涉及)

对于创建的用户 syl001 来说,此时未授予其任何权限。

如下示例:

# 首先,我们创建一个 shiyanlou002 数据库,并在其中创建一张 test 表作为演示示例
mysql> create database shiyanlou002;
Query OK, 1 row affected (0.00 sec)
mysql> use shiyanlou002;
Database changed
mysql> create table test(name varchar(10), age int);
Query OK, 0 rows affected (0.35 sec)

这时,我们新打开一个终端,避免后面来回切换用户。

# 使用 syl001 用户进行登陆。只能查看 MySQL 系统的信息数据库
shiyanlou@:~$ mysql -u syl001 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
...
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)

然后换到 root 用户的终端,授予其访问 test 表的 name 列的插入和更新的权限。

mysql> GRANT INSERT(name), UPDATE(name) ON shiyanlou002.test TO "syl001"@localhost;
Query OK, 0 rows affected (0.28 sec)
# 接着,再次使用 syl001 进行操作
mysql> insert into shiyanlou002.test(name) values("h");
Query OK, 1 row affected (0.28 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| shiyanlou002       |
+--------------------+

# 因为在上面的内容中,我们只给予了其插入和更新 name 列的权限,所以执行查询和删除操作都会被拒绝,如下所示:

mysql> select * from shiyanlou002.test;
ERROR 1142 (42000): SELECT command denied to user 'syl001'@'localhost' for table 'test'

mysql> delete from shiyanlou002.test where name="h";
ERROR 1142 (42000): DELETE command denied to user 'syl001'@'localhost' for table 'test'

需要注意的是,如果给予了用户全局的权限,尽管其不具备对低于全局的特权级别,如某个数据库的权限,该用户对于该数据库的操作也会被执行。

5. 撤销授权

对应 GRANT,撤销授权的语法为 REVOKE:

REVOKE
    priv_type [(column_list)]
      [, priv_type [(column_list)]] ...
    ON priv_level
    FROM user [, user] ...

如下示例,撤销 syl001 对于 shiyanlou002.test 表中 name 列的插入权限。需要切换到 root 用户登录的终端:

mysql> REVOKE INSERT(name) ON shiyanlou002.test FROM "syl001"@"localhost";
Query OK, 0 rows affected (0.00 sec)

到 syl001 用户的终端执行。

# 这时,再次插入时就会失败,只能更新 name 列,因为更新权限还未被撤销
mysql> insert into shiyanlou002.test(name) values("h");
ERROR 1142 (42000): INSERT command denied to user 'syl001'@'localhost' for table 'test'

mysql> update shiyanlou002.test set name="shiyanlou";
Query OK, 1 rows affected (0.30 sec)
Rows matched: 1  Changed: 1  Warnings:0

MySQL 权限和账号管理操作视频:

6. 总结

通过本节实验一起学习了 MySQL 中的访问控制权限,用户的权限管理操作,以及授权用户和撤销授权等。

results matching ""

    No results matching ""