小项目之仿优酷
# 储备知识
我们得弄清 cookies、session、token 到底是什么?!
参考文档:https://www.cnblogs.com/liuqingzheng/articles/8990027.html
何为会话?
会话,广义的含义是指有始有终的一系列动作/消息.
在web中,会话对象用来存储特定用户会话所需的属性及配置信息!
HTTP协议是无状态协议?
无状态协议即无法保持会话之间的状态.服务端不晓得客户端是什么状态.
HTTP请求是无状态的,每次都是新的请求!
举个例子,成功登陆一个网站,当访问该网站的其它网页时,该登陆状态会消失!需要重新登陆一次.
此时,我们需要将对应的会话信息(eg:登陆成功的信息等)保存下来 -- Cookie 或 Session!
会话信息的保存:
cookie 客户端 ; session 服务端 ; token 客户端
注意.不管是cookie还是token,只要保存在客户端的信息,我们都统称为cookie信息.
无cookie时期 -- 静态网站
cookie认证时期 -- 在线购物网站、需要登录的网站等
当一个浏览器访问某web服务器时
web服务器会在响应头中添加一个名叫Set-Cookie的响应字段,用于将Cookie返回给浏览器
当浏览器第二次访问该web服务器时会自动的将该cookie回传给服务器,来实现用户状态跟踪!!
弊端:
尽管浏览器发送登陆信息(pwd)会加密发送到服务端,
进而服务端返还给客户端的cookie中包含的是客户端/浏览器加密的密码..
但cookie中始终包含着pwd这些用户的敏感信息.
不管是用户首次登陆发送给S端的数据包,还是C-->S的cookie,黑客截获后可以通过撞库破解.
为了降低风险,我们可以将C-->S的cookie信息中不包含pwd等用户的敏感信息
cookie+session认证时期
打个比方,将自己比作服务端,给大家发一个会话标识(session id),说白了就是一个随机的字串
每个人收到的都不一样,每次大家向我发起HTTP请求的时候,把这个session字串放到cookie中一并捎过来
我在服务端将其与存储的session进行比对,这样我就能区分开谁是谁了!
弊端:
1> 每个人只需要保存自己的session id,而服务器要保存所有人的session id !
随着访问服务端的用户增多,S端存储的session也会变多!
2> 若同时有10万个并发访问S端,S端收到了10万份包含了session的cookie,需要一一进行比对..
3> 倘若用两个机器组成了一个集群,小F通过机器A登录了系统,那session id会保存在机器A上
假设小F的下一次请求被转发到机器B怎么办?机器B可没有小F的 session id啊.
限制了集群的水平扩展.
解决办法:
session sticky
就是让小F的请求一直粘连在机器A上,但是这也不管用,要是机器A挂掉了,还得转到机器B去.
session的复制
把session id在两个机器之间搬来搬去!
session的集群
将多台服务器的session集中管理,放到一处,并对该session做集群,避免单点故障.
Token
服务端为什么要保存这可恶的session呢,只让每个客户端去保存该多好!
So,Token用计算换取了空间!
小F已经成功登录系统,我给他发一个令牌(token),里边包含了小F的user id,并对该数据做一个签名
比如说我用HMAC-SHA256算法,加上一个只有我才知道的密钥,对数据做一个签名
把 这个签名和数据一起作为token `即签名+数据=token` 发送给C端,由于密钥别人不知道,就无法伪造token了!!
这个token我不保存,当小F把这个token给我发过来的时候,我再用同样的HMAC-SHA256算法和同样的密钥
对数据再计算一次签名和token中的签名做个比较
若相同,我就知道小F已经登录过了,并且可以直接取到小F的user id;
若不相同,数据部分肯定被人篡改过,我就告诉发送者:对不起,没有认证!
Ps:Token移动端也可以用!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 仿优酷项目
该项目涵盖内容: 线程池, 锁机制, session验证机制, 简易版orm, 大文件md5校验, 数据库操作
# 系统架构
Ps: 偷个懒吧,不想画图!!直接拍照完事. 随缘画法.
# 创建表
用sql语句 or 用工具创建表
Ps: 加` `是为了表明它不是关键字,若不加,美化后,它就变成大写的了!
用工具创建类型为timestamp的字段时,若勾选"根据当前时间更新",添加和修改数据时,都会更新时间!
-- 关掉外键约束,表明不用做外键检查,两表有外键关联,也能删除!
set foreign_key_checks = 0;
-- 若表已存在,删除.
drop table if exists user_info,movie,notice,download_record;
-- 用户表
CREATE TABLE user_info (
id INT PRIMARY KEY NOT NULL auto_increment,
`name` VARCHAR ( 32 ),
`password` VARCHAR ( 64 ),
is_vip INT, -- 是否是会员
locked INT, -- 是否锁定
user_type VARCHAR ( 32 ) -- 管理员还是普通用户
) ENGINE = INNODB,
charset = 'utf8';
-- 视频表
CREATE TABLE movie (
id INT PRIMARY KEY NOT NULL auto_increment,
`name` VARCHAR ( 32 ),
`path` VARCHAR ( 255 ),
is_free INT DEFAULT 0, -- 是否收费
is_delete INT DEFAULT 0,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 自动添加当前时间戳为上传时间.
user_id INT, -- 谁上传的视频
file_md5 VARCHAR ( 64 )
) charset = 'utf8';
-- 公告表
CREATE TABLE notice (
id INT PRIMARY KEY NOT NULL auto_increment,
`name` VARCHAR ( 64 ),
content VARCHAR ( 255 ),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
user_id INT
) charset = 'utf8';
-- 下载记录表
CREATE TABLE download_record (
id INT NOT NULL PRIMARY KEY auto_increment,
user_id INT,
movie_id INT
) charset = 'utf8';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 搭建项目目录
.
├── youkuClient
│ ├── conf
│ │ └── setting.py
│ ├── core
│ │ ├── admin.py # -- 管理员视图相关功能函数
│ │ ├── src.py # -- 主视图
│ │ └── user.py # -- 用户视图相关功能函数
│ ├── lib
│ │ └── common.py # -- 存放公共方法
│ ├── start.py # -- 启动文件
│ └── tcpClient
│ └── tcp_client.py # -- 客户端连接
└── youkuServer
├── conf
│ └── setting.py
├── db
│ └── models.py # -- 数据库表对应程序中的类
├── interface
│ ├── admin_interface.py # -- 管理员相关操作的接口
│ ├── common_interface.py # -- 公共操作的相关接口(登录,注册)
│ └── user_interface.py # -- 用户相关操作的接口
├── lib
│ └── common.py
├── start.py
└── tcpServer
└── tcp_server.py
.
├── youkuClient
│ ├── conf
│ │ └── setting.py # -- 配置信息相关
│ ├── core
│ │ ├── admin.py # -- 管理员视图相关功能函数
│ │ ├── src.py # -- 主视图
│ │ └── user.py # -- 用户视图相关功能函数
│ ├── download_movie # -- 存放下载完的电影
│ ├── lib
│ │ └── common.py # -- 存放公共方法
│ ├── start.py # -- 启动文件
│ ├── tcpClient # -- 存放要上传的电影
│ │ └── tcp_client.py # -- 客户端连接
│ └── upload_movie
└── youkuServer
├── conf
│ └── setting.py
├── db
│ └── models.py
├── interface
│ ├── admin_interface.py # -- 管理员相关操作的接口
│ ├── common_interface.py # -- 公共操作的相关接口(登录,注册)
│ └── user_interface.py # -- 用户相关操作的接口
├── lib
│ └── common.py
├── movie_list
├── orm_pool # -- 简易版的ORM框架
│ ├── db_pool.py
│ ├── mysql_conn.py
│ └── todo_orm.py
├── start.py
└── tcpServer
├── tcp_server.py # -- 服务端核心代码
└── use_data.py # -- 存放用户信息和全局锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
ORM框架
> 定义字段类表示表中的列
> 实现不用写__init__,类实例化时可以传任意类型的k=v,把参数放到实例对象的体内 -- 字典
> 实现字典对象通过 . 访问到属性 -- __getattr__、__setattr__
> 用一个类表示数据库当中的一个表,所有的类都得具备表的几个属性(表名、主键、一堆字段)
但这些属性的值每张表都不相同.通过控制类的创建过程,让类创建好后就有这几个东西 -- 元类
> 不写sql 类对应数据库当中的表,类的一个实例对应表中的一条数据
查询所有数据 -- 类方法
更新、新增 -- 实例绑定方法
(构建sql语句、pymysql接口返回结果)
> 数据库连接池
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11