CategoryResourceRepost/极客时间专栏/MySQL 必知必会/进阶篇/18 | 权限管理:如何控制数据库访问,消除安全隐患?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

317 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="18 | 权限管理:如何控制数据库访问,消除安全隐患?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d4/33/d4c1ce6debd0c28a2272429250a58433.mp3"></audio>
你好,我是朱晓峰,今天,我来和你聊一聊权限管理。
我们在开发应用的时候,经常会遇到一种需求,就是要根据用户的不同,对数据进行横向和纵向的分组。
所谓横向的分组,就是指用户可以接触到的数据的范围,比如可以看到哪些表的数据;所谓纵向的分组,就是指用户对接触到的数据能访问到什么程度,比如能看、能改,甚至是删除。
我们把具有相同数据访问范围和程度的用户归成不同的类别,这种类别就叫角色。通过角色,管理用户对数据库访问的范围和程度就更加方便了。这也就是对用户的数据访问权限的管理。
**恰当的权限设定,可以确保数据的安全性,这是至关重要的**
那么,怎么进行权限管理呢?这节课,我就结合超市项目的实际案例,给你讲一下权限管理的具体操作,包括怎么操作角色和用户,怎么通过角色给用户授权,怎么直接给用户授权,从而帮助你管理好用户的权限,提升数据库的安全性。
下面我就来先讲讲角色。我们可以通过角色对相同权限的用户进行分组管理,这样可以使权限管理更加简单高效。
## 角色的作用
角色是在MySQL 8.0中引入的新功能,相当于一个权限的集合。引入角色的目的是方便管理拥有相同权限的用户。
下面我举个超市项目中的例子,来具体说明一下如何通过角色管理用户权限。
超市项目中有库管、营运和财务等不同的模块它们各自对应不同的数据表。比如库存模块中的盘点表demo.invcount、营运模块中的商品信息表demo.goodsmaster还有财务模块中的应付账款表demo.settlement。下面是这些表的具体信息。
盘点表:
<img src="https://static001.geekbang.org/resource/image/81/28/812f141d6f1f7fb85a2c797a3c666528.jpeg" alt="">
商品信息表:
<img src="https://static001.geekbang.org/resource/image/00/dd/00151b4b837c70fc5d7516b3307cf8dd.jpeg" alt="">
应付账款表:
<img src="https://static001.geekbang.org/resource/image/81/c6/81c3b5cd0937fca32b0a54847170cec6.jpeg" alt="">
在超市项目中,员工的职责不同,包括库管、营运和财务等,不同的职责有不同的数据访问权限。比如:
- 张三是库管,他就可以查询商品信息表,对盘点表有增删改查的权限,但无权访问应付账款表;
- 李四是营运,他就拥有对商品信息表有增删改查的权限,而对库存表和应付账款表,只有查看的权限;
- 王五是财务,他就有对应付账款表有增删改查的权限,对商品信息表和库存表,只有查看的权限。
所以,我们需要为每一个职责创建一个对应的角色,为每个员工创建一个对应的数据库用户。然后通过给角色赋予相关的权限,再把角色赋予用户,实现对超市员工访问数据权限的管理,从而保证数据的安全性。
这样说有点抽象,下面我们具体操作一下角色和用户。
## 如何操作角色?
首先,我们要创建一个角色,为后面的授权做好准备。
### 如何创建角色?
MySQL中的角色名称由角色名称加主机名称组成。创建角色的语法结构如下
```
CREATE ROLE 角色名;
```
假设我们现在需要创建一个经理的角色,就可以用下面的代码:
```
mysql&gt; CREATE ROLE 'manager'@'localhost';
Query OK, 0 rows affected (0.06 sec)
```
这里的意思是创建一个角色角色名称是“manager”角色可以登录的主机是“localhost”意思是只能从数据库服务器运行的这台计算机登录这个账号。你也可以不写主机名直接创建角色“manager”
```
mysql&gt; CREATE ROLE 'manager';
Query OK, 0 rows affected (0.01 sec)
```
如果不写主机名MySQL默认是通配符“%”,意思是这个账号可以从任何一台主机上登录数据库。
同样道理,如果我们要创建库管的角色,就可以用下面的代码:
```
mysql&gt; CREATE ROLE 'stocker';
Query OK, 0 rows affected (0.02 sec)
```
**创建角色之后,默认这个角色是没有任何权限的,我们需要给角色授权**
### 怎么给角色赋予权限?
给角色授权的语法结构是:
```
GRANT 权限 ON 表名 TO 角色名;
```
假设我们现在想给经理角色授予商品信息表、盘点表和应付账款表的只读权限,就可以用下面的代码来实现:
```
mysql&gt; GRANT SELECT ON demo.settlement TO 'manager';
Query OK, 0 rows affected (0.03 sec)
mysql&gt; GRANT SELECT ON demo.goodsmaster TO 'manager';
Query OK, 0 rows affected (0.01 sec)
mysql&gt; GRANT SELECT ON demo.invcount TO 'manager';
Query OK, 0 rows affected (0.01 sec)
```
如果我们需要赋予库管角色盘点表的增删改查权限、商品信息表的只读权限,对应付账款表没有权限,就可以这样:
```
mysql&gt; GRANT SELECT,INSERT,DELETE,UPDATE ON demo.invcount TO 'stocker';
Query OK, 0 rows affected (0.02 sec)
mysql&gt; GRANT SELECT ON demo.goodsmaster TO 'stocker';
Query OK, 0 rows affected (0.02 sec)
```
### 查看角色权限
赋予角色权限之后我们可以通过SHOW GRANTS语句来查看权限是否创建成功了
```
mysql&gt; SHOW GRANTS FOR 'manager';
+-------------------------------------------------------+
| Grants for manager@% |
+-------------------------------------------------------+
| GRANT USAGE ON *.* TO `manager`@`%` |
| GRANT SELECT ON `demo`.`goodsmaster` TO `manager`@`%` |
| GRANT SELECT ON `demo`.`invcount` TO `manager`@`%` |
| GRANT SELECT ON `demo`.`settlement` TO `manager`@`%` |
+-------------------------------------------------------+
4 rows in set (0.00 sec)
```
只要你创建了一个角色系统就会自动给你一个“USAGE”权限意思是连接登录数据库的权限。代码的最后三行代表了我们给角色“manager”赋予的权限也就是对商品信息表、盘点表和应付账款表的只读权限。
再来看看库管角色的权限:
```
mysql&gt; SHOW GRANTS FOR 'stocker';
+----------------------------------------------------------------------------+
| Grants for stocker@% |
+----------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `stocker`@`%` |
| GRANT SELECT ON `demo`.`goodsmaster` TO `stocker`@`%` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `demo`.`invcount` TO `stocker`@`%` |
+----------------------------------------------------------------------------+
3 rows in set (0.00 sec)
```
结果显示,库管角色拥有商品信息表的只读权限和盘点表的增删改查权限。
当我们需要对业务重新整合的时候,可能就需要对之前创建的角色进行清理,删除一些不会再使用的角色。
### 删除角色
删除角色的操作很简单,你只要掌握语法结构就行了。
```
DROP ROLE 角色名称;
```
这个操作十分简单,我就不多说了。
到这里,关于角色的操作,我就介绍完了,下面我们来看看关于用户的操作。
## 如何操作用户?
我们可以把数据库中的角色看作是一个权限集。角色本身不能操作数据,这个任务还是要靠用户来完成。在操作用户前,我们先要创建一个用户。
### 创建用户
创建用户的语法结构是这样的:
```
CREATE USER 用户名 [IDENTIFIED BY 密码];
```
“[ ]”表示可选,也就是说,可以指定用户登录时需要密码验证,也可以不指定密码验证,这样用户可以直接登录。不过,不指定密码的方式不安全,不推荐使用。
举个例子假设我们要给张三创建一个用户用户名是“zhangsan”密码是“mysql”可以通过下面的代码来实现
```
mysql&gt; CREATE USER 'zhangsan' IDENTIFIED BY 'mysql';
Query OK, 0 rows affected (0.02 sec)
```
这样,张三的用户就创建成功了。
### 给用户授权
给用户授权的方式有2种分别是通过把角色赋予用户给用户授权和直接给用户授权。
通过把角色赋予用户给用户授权的语法结构如下:
```
GRANT 角色名称 TO 用户名称;
```
举个小例子,我们想要给张三赋予库管的角色,可以通过下面的代码实现:
```
mysql&gt; GRANT 'stocker' TO 'zhangsan';
Query OK, 0 rows affected (0.01 sec)
```
我们也可以直接给用户授权,语法结构如下:
```
GRANT 权限 ON 表名 TO 用户名;
```
这种方式简单直接,我就不多说了。下面我们来查看一下这个用户的权限有哪些。
### 查看用户权限
查看用户权限的语法结构是:
```
SHOW GRANTS FOR 用户名;
```
我们可以通过下面的代码来查看张三的权限:
```
mysql&gt; SHOW GRANTS FOR 'zhangsan';
+---------------------------------------+
| Grants for zhangsan@% |
+---------------------------------------+
| GRANT USAGE ON *.* TO `zhangsan`@`%` |
| GRANT `stocker`@`%` TO `zhangsan`@`%` |
+---------------------------------------+
2 rows in set (0.00 sec)
```
结果显示,张三拥有库管角色的权限。
说到这里,我必须要提醒你一个常见的坑。
如果现在你用张三的这个用户去登录你会发现这个账号是没有任何权限的。你是不是觉得很奇怪我不是把角色“stocker”赋予用户“zhangsan”了吗那用户“zhangsan”应该有角色“stocker”的权限啊。其实这是因为**MySQL中创建了角色之后默认都是没有被激活的**,也就是不能用,必须要用下面的语句激活:
```
SET global activate_all_roles_on_login=ON;
```
这条SQL语句的意思是对所有角色永久激活。运行这条语句之后用户“zhangsan”才真正拥有了角色“stocker”的所有权限。
下面我们就用张三的账号登录,确认一下他有没有相应的权限:
```
H:\&gt;mysql -u zhangsan -p
Enter password: *****
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 8.0.23 MySQL Community Server - GPL
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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&gt; select * from demo.goodsmaster;
+------------+---------+-----------+---------------+------+------------+----------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice | avgimportprice |
+------------+---------+-----------+---------------+------+------------+----------------+
| 1 | 0001 | 书 | 16开 | 本 | 89.00 | 31.00 |
| 2 | 0002 | 笔 | NULL | 包 | 5.00 | 2.87 |
+------------+---------+-----------+---------------+------+------------+----------------+
2 rows in set (0.02 sec)
```
结果显示,我们可以正常登录,并且可以查询商品信息表的内容。
### 删除用户
当用户不再使用的时候,我们也可以删除用户。操作起来很简单,你只要知道语法结构就行了:
```
DROP USER 用户名;
```
## 总结
今天这节课,我们学习了权限管理的方法,包括如何操作角色和用户,如何通过角色给用户授权,如何直接给用户授权等。
角色是权限的集合。你可以直接给用户授予访问数据库的权限,也可以通过把角色授予用户,从而把角色对数据库的访问权限全部授予给用户。而用户是数据库的使用者,我们可以通过给用户授予访问数据库中资源的权限,来控制使用者对数据库的访问,消除安全隐患。
需要注意的是,角色在刚刚创建出来的时候,默认是没有激活的,需要手动激活,才可以使用。如果你把角色赋予了用户,那么用户就拥有了角色的全部权限。但是,如果你删除了角色,那么用户也就失去了通过这个角色所获得的所有权限。
我知道有一些程序员喜欢使用Root超级用户来访问数据库完全把权限控制放在应用层面实现。这样当然也是可以的。不过我建议你尽量使用数据库自己的角色和用户机制来控制访问权限不要轻易用Root账号。因为Root账号密码放在代码里面不安全一旦泄露数据库就会完全失去保护。而且MySQL的权限控制功能十分完善应该尽量利用可以提高效率而且安全可靠。
## 思考题
在今天的课里我举了一个例子提到超市运营中的一个职责“财务”。财务可以对商品信息表、盘点表有只读的权限对应付账款表有增删改查的权限。请你设计一个角色财务“accountant”具备这些权限。给会计“李四”创建一个用户账号“lisi”使李四通过财务的角色获得对应付账款表增删改查的权限和对商品信息表、盘点表有只读的权限。
欢迎在留言区写下你的思考和答案,我们一起交流讨论。如果你觉得今天的内容对你有所帮助,也欢迎你分享给你的朋友或同事,我们下节课见。