jwt解析不可await,因jwt.decode()是同步cpu操作;须先同步提取token并解出sub/user_id(不验签),再await异步查库验证权限与有效性。

FastAPI异步中间件里JWT解析不能await
JWT校验本身是纯CPU操作,jwt.decode() 同步执行即可,强行包进 await asyncio.to_thread() 反而引入线程调度开销,拖慢响应。真正要异步的是后续查库动作——比如根据 sub 查用户角色、权限树或token是否被撤销。
常见错误写法:await jwt.decode(...)(语法报错)或 await asyncio.to_thread(jwt.decode, ...)(没必要)
正确做法分两步:
- 用
Authorizationheader 提取 token 字符串(同步) - 用
jwt.decode(token, options={"verify_signature": False})同步解出sub或user_id(不验签,避免阻塞) - 再用
await db.execute(...)异步查库验证有效性与权限(必须异步)
限流中间件别用固定窗口算法
固定窗口(如“每分钟最多10次”)在窗口切换边界容易被绕过:前一秒发10次,后一秒又发10次,实际2秒内就扛了20次请求。生产环境推荐滑动窗口或令牌桶。
slowapi 默认是固定窗口,但支持配置为滑动窗口;async-ratelimiter 的 Limiter 底层是平滑的令牌桶,更适合突发流量场景。
选型建议:
- 做全局限流(防刷IP)→ 用
slowapi+ Redis 后端(需配SlowAPIMemoryBackend或SlowAPIRedisBackend) - 做用户级/接口级细粒度控制 → 用
async-ratelimiter配合request.state.user_id动态构造限流键 - 高并发网关层 → 必须上 Redis,内存限流只适合单机低QPS服务
中间件顺序错会导致鉴权失效
FastAPI中间件执行顺序严格依赖注册顺序。如果把限流中间件放在鉴权中间件之后,攻击者可能先触发限流失败,再绕过鉴权直接打接口;反之,如果鉴权在前但没校验成功就放行,限流规则又对未授权请求生效,浪费资源。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
安全顺序只能是:
- 先做基础校验(CORS、Content-Type、Header格式)
- 再做鉴权(提取并验证 JWT,查用户权限)
- 最后做限流(此时已知
user_id、schema、client_ip,可做分级限流)
在 server.py 中,对应代码位置应为:
app.add_middleware(AuthMiddleware) # ← 必须在 rate limiter 前 app.add_middleware(RateLimitMiddleware)
异步中间件里别混用同步DB驱动
在 async def __call__ 中调用 psycopg2.connect 或 sqlite3.connect 会阻塞事件循环,导致整个服务吞吐骤降。哪怕只是查一次 Redis,也得用 aioredis 或 redis-py 的 async client。
典型症状:压测时 CPU 不高,但平均延迟飙升、协程堆积、asyncio.TimeoutError 频发。
检查项:
- 确认 DB 连接对象是
AsyncSession(SQLModel/SQLAlchemy 1.4+)或asyncpg.Pool - Redis 客户端是否为
aioredis.Redis,不是redis.Redis - 所有
.execute()、.get()、.incr()调用前都有await
最容易被忽略的是日志中间件里偷偷调用了同步配置读取或本地文件写入——这些都得挪到 startup event 里预加载,或改用 await asyncio.to_thread(open, ...) 包装。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










