在 Flask 项目中集成 JWT 认证,最推荐直接使用 Flask-JWT-Extended 扩展库,适用于无状态的 API 身份验证场景。需要注意令牌必须通过 HTTPS 传输,且服务端需妥善保管密钥以防伪造。
先说结论:Flask 集成 JWT 应优先选用 Flask-JWT-Extended 扩展,通过 access_token 处理业务请求,refresh_token 处理令牌更新。
- 适合:前后端分离架构、移动端 API 接口、微服务间调用。
- 先看:JWT 密钥配置、令牌过期时间策略、HTTPS 传输加密。
- 建议:将 refresh_token 存储在 HttpOnly Cookie 中,access_token 存储在内存或本地存储。
命令速用版
通过 pip 安装官方维护的扩展库,确保依赖环境干净。
pip install Flask-JWT-Extended为什么会这样
JWT 认证的核心优势在于服务端无需存储会话状态,适合横向扩展的分布式系统。Access Token 有效期短,用于日常请求验证;Refresh Token 有效期长,用于在 Access Token 过期后换取新令牌,避免用户频繁重新登录。这种双令牌机制平衡了安全性与用户体验,但要求客户端具备妥善存储令牌的能力。
分步处理
按照初始化、登录发证、接口保护、令牌刷新四个步骤实施,每步完成后需检查日志或响应状态。
1. 初始化扩展与配置
在 Flask 应用工厂中初始化 JWT 管理器,设置密钥和算法。密钥必须通过环境变量读取,禁止硬编码在代码中。
from flask import Flask
from flask_jwt_extended import JWTManager
app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "从环境变量读取的强随机字符串"
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = 3600 # 单位秒
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = 86400 * 30
jwt = JWTManager(app)2. 创建登录接口发放令牌
验证用户账号密码成功后,调用 create_access_token 和 create_refresh_token 生成令牌对。
from flask_jwt_extended import create_access_token, create_refresh_token
@app.route('/login', methods=['POST'])
def login():
# 此处添加验证 username/password 的逻辑
identity = "user_id"
access_token = create_access_token(identity=identity)
refresh_token = create_refresh_token(identity=identity)
return {"access_token": access_token, "refresh_token": refresh_token}3. 保护需要认证的路由
使用 jwt_required 装饰器拦截请求,自动验证 Access Token 的有效性。
from flask_jwt_extended import jwt_required, get_jwt_identity
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return {"logined_as": current_user}4. 实现令牌刷新接口
当 Access Token 过期时,客户端携带 Refresh Token 请求此接口换取新的 Access Token。
from flask_jwt_extended import jwt_required, create_access_token
@app.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
current_user = get_jwt_identity()
new_access_token = create_access_token(identity=current_user)
return {"access_token": new_access_token}怎么验证是否生效
使用 curl 或 Postman 模拟请求流程,观察状态码和返回内容。
1. 测试登录
发送 POST 请求到/login,确认返回 JSON 中包含 access_token 和 refresh_token 字段。
2. 测试受保护接口
携带 access_token 访问/protected,Header 中设置 Authorization: Bearer <token>,应返回 200 状态码和用户信息。
3. 测试令牌过期
等待 access_token 过期后再次请求/protected,应返回 401 状态码。随后携带 refresh_token 请求/refresh,获取新 access_token 后重试成功。
常见坑
- 密钥泄露风险:JWT_SECRET_KEY 若被泄露,攻击者可伪造任意用户令牌。务必使用高熵随机字符串,并定期轮换。
- HTTP 明文传输:令牌在 HTTP 下传输容易被中间人窃取。生产环境必须强制启用 HTTPS。
- 令牌存储不当:将令牌存储在 localStorage 易受 XSS 攻击。建议 refresh_token 存入 HttpOnly Cookie,access_token 存入内存变量。
- 缺少注销机制:JWT 默认无状态,无法直接服务端注销。需结合令牌黑名单或短有效期策略实现逻辑注销。
常见问题
JWT 令牌过期时间设置多少合适?
Access Token 建议设置为 15 分钟到 1 小时,Refresh Token 建议设置为 1 天到 30 天。具体时间需根据业务安全等级调整,高敏感业务应缩短 access_token 有效期。
如何实现用户注销功能?
JWT 本身不支持服务端主动失效令牌。可以通过维护一个令牌黑名单数据库,或在 Redis 中存储已注销的令牌 ID,在 jwt_required 校验时拦截黑名单中的令牌。
令牌应该放在 Header 还是 Cookie 中?
API 接口通常放在 Authorization Header 中,格式为 Bearer <token>。Web 端为防御 CSRF,建议将 refresh_token 放在 HttpOnly Cookie 中,access_token 放在内存中。
参考来源
- Flask-JWT-Extended Official Documentation, "Basic Usage", https://flask-jwt-extended.readthedocs.io/en/latest/
- RFC 7519, "JSON Web Token (JWT)", https://datatracker.ietf.org/doc/html/rfc7519