Cookie
Cookie 是一种小型文本文件,保存在客户端的浏览器中,每个 Cookie 的大小一般不超过 4KB。每个 Cookie 可以设置 过期时间,过期后 Cookie 将被删除。一个 Cookie 包含:Name, Value, Domain, Path, Expires/Max-Age, Size, HttpOnly, Secure, SameSite, Partion Key Site, Cross Site, Priority。
-
名称 (Name) 和 值 (Value):存储的实际内容。
-
过期时间 (Expires/Max-Age):决定 Cookie 的生命周期。
-
作用域 (Path 和 Domain):控制 Cookie 的有效路径和域,
Path=/
:表示整个网站都可以访问该 Cookie。 -
安全标志 (Secure 和 HttpOnly):
-
Secure
:只有在 HTTPS 下传输。 -
HttpOnly
:禁止 JavaScript 访问,防止 XSS 攻击。
-
下面四个是不太常用的:
- SameSite (同站属性):控制 Cookie 在跨站请求中是否会被发送,主要用于防范 跨站请求伪造(CSRF) 攻击。
- Partitioned Key Site(分区 Key Cookie):是浏览器在隐私保护政策下引入的一种机制,用于限制第三方 Cookie 的跨站共享。
- Cross-Site(跨站请求):指 Cookie 在不同域名之间的传输行为,例如从站点
A.com
发起请求到站点B.com
,这被视为跨站请求。 - Priority(Cookie 优先级):用于指定 Cookie 的重要程度,浏览器在面对内存压力或存储空间不足时,会根据优先级删除低优先级的 Cookie。
Session
服务器会为一个客户端的每次会话生成一个 Session 存放在服务器(可以存放在服务器的数据库中),Session 主要包括的内容可能有(主要有服务器决定):
- Session ID:唯一标识符。
- 用户身份信息:如用户 ID 和登录状态。
- 用户个性化数据:如偏好设置。
- 临时状态数据:如购物车数据。
- 访问控制信息:如角色和权限。
- 会话超时与过期信息:确保 Session 生命周期安全。
- 安全校验数据:防止篡改和攻击。
- 其他业务数据:根据具体应用场景而定。
服务器会把 Session ID 发送给客户端存放在客户端的 Cookie 并设置过期时间,Session ID 是一个字符串,生成规则一般由服务器决定,每个会话的 Session ID 都是唯一的,以避免会话冲突。
工作原理:
- 用户首次访问时,服务器生成一个唯一的 Session ID 并存储在服务器。
- 服务器将 Session ID 发送给客户端,通常通过 Cookie 传输。
- 客户端后续的请求都会携带该 Session ID。
- 服务器根据 Session ID 找到对应的 Session 数据,从而识别用户身份。
Python 代码示例:
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
from flask import Flask, session, request, jsonify, redirect, url_for
from datetime import timedelta
app = Flask(__name__)
app.secret_key = "secret_key_for_session" # 用于加密 Session 数据
app.permanent_session_lifetime = timedelta(minutes=30) # 设置 Session 过期时间为30分钟
@app.route('/')
def home():
if "username" in session:
return f"Welcome back, {session['username']}!"
return "Hello! Please log in"
@app.route('/login', methods=['POST'])
def login():
# 模拟用户登录,获取用户名
username = request.form.get('username')
if username:
session['username'] = username # 将用户名存储到 Session 中
session.permanent = True # 激活 Session 过期时间
return jsonify({"message": f"Hello, {username}. You are logged in!"})
return jsonify({"error": "Username is required"}), 400
@app.route('/logout')
def logout():
# 删除 Session 数据
session.pop('username', None)
return jsonify({"message": "You have been logged out."})
@app.route('/profile')
def profile():
# 读取 Session 数据
if 'username' in session:
username = session['username']
return jsonify({"message": f"Welcome, {username}. This is your profile."})
return jsonify({"error": "You are not logged in."}), 401
if __name__ == '__main__':
app.run(debug=True)
Token
Token 是一种身份验证机制,通常基于加密签名生成的字符串。常用的 Token 形式包括 JWT(JSON Web Token)。
一个标准的 JWT 包含三部分:
- Header(头部):Token 类型和签名算法。
- Payload(负载):包含用户身份信息和自定义字段。
- Signature(签名):对 Header 和 Payload 进行加密签名。
例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTYifQ.4Q6wA9fx...
。
工作原理:
- 用户登录时,服务器验证用户信息,并生成 Token 返回给客户端。
- 客户端将 Token 保存在本地,后续请求时将 Token 放入 HTTP Header。
- 服务器验证 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
55
import jwt
import datetime
from flask import Flask, request, jsonify
app = Flask(__name__)
SECRET_KEY = "secret_key_for_token" # 用于加密和解密 Token
# 生成 Token
def generate_token(username):
payload = {
"username": username,
"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=30) # 过期时间
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return token
# 验证 Token
def verify_token(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
return None # Token 过期
except jwt.InvalidTokenError:
return None # Token 无效
@app.route('/login', methods=['POST'])
def login():
# 模拟用户登录
username = request.form.get('username')
if username:
token = generate_token(username)
return jsonify({"message": "Login successful", "token": token})
return jsonify({"error": "Username is required"}), 400
@app.route('/profile')
def profile():
# 从请求头获取 Token
token = request.headers.get('Authorization')
if token:
token = token.split("Bearer ")[-1] # 提取 Token 部分
payload = verify_token(token)
if payload:
username = payload['username']
return jsonify({"message": f"Welcome, {username}. This is your profile."})
return jsonify({"error": "Invalid or expired token."}), 401
return jsonify({"error": "Token is required."}), 401
@app.route('/logout')
def logout():
# 由于 Token 是无状态的,不需要存储,无法强制失效
return jsonify({"message": "Token invalidation is client-side. Simply discard it."})
if __name__ == '__main__':
app.run(debug=True)