
当服务器发出一个重定向响应(例如HTTP状态码301、302、303、307、308)时,它实际上是告诉浏览器“你请求的资源现在在另一个地方,请去那里重新请求”。浏览器接收到这个重定向指令后,会根据响应头中的Location字段指定的URL,发起一个全新的HTTP请求。
关键在于,这个由浏览器发起的后续请求是一个独立的请求。服务器在重定向响应中设置的任何自定义HTTP头(例如,你期望的Authorization头)都不会被浏览器自动“携带”到这个新的请求中。浏览器只会遵循HTTP协议规范,发送它通常会发送的头(如Host、User-Agent、以及与目标URL相关的Cookie等)。因此,直接通过重定向响应来为后续请求设置自定义请求头,在HTTP协议层面是不可行的。
鉴于上述限制,将JWT令牌安全地从一个页面传递到另一个页面的标准做法是利用HTTP Cookie机制。通过将JWT存储在服务器设置的Cookie中,浏览器会在后续对同一域名的请求中自动携带这个Cookie,从而实现令牌的传递。为了确保安全性,我们必须配置Cookie的几个关键属性:
以下是如何在Flask中修改你的注册逻辑,以便通过HttpOnly Cookie安全地传递JWT令牌:
import jwt
import datetime
from flask import Flask, redirect, url_for, make_response, request
# 假设你已经定义了SECRET、数据库操作等
SECRET = "your_super_secret_key" # 在生产环境中应从环境变量获取
app = Flask(__name__)
# 模拟数据库操作和用户ID生成
def generate_customer_id():
return "user_" + str(datetime.datetime.now().timestamp()).replace('.', '')
def store_customer_in_db(cid, hashed_passwd):
# 模拟存储到数据库
print(f"Storing user {cid} with hashed password {hashed_passwd} in DB.")
return True
@app.route('/signup', methods=['POST'])
def signup():
# 假设从请求中获取用户名和密码
username = request.form.get('username')
password = request.form.get('password')
if not username or not password:
return "Username and password are required", 400
# 模拟用户注册和密码哈希
cid = generate_customer_id()
hashed_passwd = f"hashed_{password}" # 实际应用中请使用安全的哈希算法如bcrypt
try:
# 模拟数据库操作
if not store_customer_in_db(cid, hashed_passwd):
raise Exception("Failed to store user in DB")
payload = {
'cid': cid,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30) # 令牌30分钟后过期
}
token = jwt.encode(payload, SECRET, algorithm='HS256')
# 创建重定向响应
redirect_url = url_for('order_page') # 使用url_for生成目标URL
response = make_response(redirect(redirect_url))
# 设置HttpOnly、Secure、SameSite Cookie
# token.decode('utf-8') 是因为 jwt.encode 返回的是 bytes
response.set_cookie(
'jwt_token',
token,
httponly=True,
secure=True, # 在生产环境中必须设置为True,本地测试可暂时设置为False
samesite='Lax', # 根据需求选择Strict或Lax
max_age=datetime.timedelta(minutes=30).total_seconds() # Cookie过期时间与JWT过期时间一致
)
return response
except Exception as err:
print(f"Error during signup: {err}")
return "Signup failed", 500
@app.route('/order')
def order_page():
# 从Cookie中获取JWT令牌
token = request.cookies.get('jwt_token')
if not token:
return "Unauthorized: No JWT token found in cookies", 401
try:
# 验证JWT令牌
decoded_payload = jwt.decode(token, SECRET, algorithms=['HS256'])
cid = decoded_payload.get('cid')
return f"Welcome to the orders page, user {cid}! Your token is valid."
except jwt.ExpiredSignatureError:
return "Unauthorized: JWT token has expired", 401
except jwt.InvalidTokenError:
return "Unauthorized: Invalid JWT token", 401
if __name__ == '__main__':
# 仅用于本地测试,生产环境应使用WSGI服务器
app.run(debug=True, ssl_context='adhoc') # 使用adhoc SSL上下文方便本地测试Secure Cookie代码解释:
通过将JWT令牌存储在配置了HttpOnly、Secure和SameSite属性的Cookie中,我们能够规避直接在URL中传递令牌的风险,并有效防止XSS和CSRF攻击。这种方法是Web应用程序中实现安全、隐蔽用户认证状态传递的推荐实践。在Flask中,通过make_response和set_cookie方法可以轻松实现这一机制。始终记住,在生产环境中启用HTTPS并正确配置Cookie的安全属性至关重要。
以上就是Flask中安全传递JWT:重定向场景下的HttpOnly Cookie实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号