Flask 如何集成 JWT 实现用户身份认证与令牌刷新

文章导读
在 Flask 项目中集成 JWT 认证,最推荐直接使用 Flask-JWT-Extended 扩展库,适用于无状态的 API 身份验证场景。需要注意令牌必须通过 HTTPS 传输,且服务端需妥善保管密钥以防伪造。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 常见问题
  7. G 参考来源
A A

在 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. 实现令牌刷新接口

Flask 如何集成 JWT 实现用户身份认证与令牌刷新

当 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