title: JWT令牌如何在FastAPI中实现安全又高效的生成与验证?

date: 2025/06/10 09:02:35

updated: 2025/06/10 09:02:35

author: cmdragon

excerpt:

JWT(JSON Web Token)是一种用于安全传递声明信息的开放标准,由头部、载荷和签名三部分组成。在FastAPI中,JWT常用于用户身份认证、API授权和跨服务通信。通过python-jose库生成和验证JWT,核心步骤包括配置安全参数、生成访问令牌、实现登录接口和验证机制。令牌生成时需设置过期时间以防止长期盗用,验证时通过中间件检查令牌的有效性。此外,可通过刷新令牌机制更新访问令牌,确保系统的安全性和用户体验。

categories:

  • 后端开发
  • FastAPI

tags:

  • JWT
  • FastAPI
  • 令牌生成
  • 令牌验证
  • 身份认证
  • 安全通信
  • 无状态会话


扫描二维码

关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意https://tools.cmdragon.cn/

第四章:JWT 令牌的生成与验证机制

1. JWT 基础概念

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在双方之间安全地传递声明信息。它由三部分组成:

  • Header(头部):描述算法和令牌类型
  • Payload(载荷):携带用户数据(如用户ID)和声明(如过期时间)
  • Signature(签名):用于验证令牌完整性的加密字符串

JWT 在 FastAPI 中的典型应用场景:

  • 用户身份认证
  • API 接口授权
  • 跨服务的安全通信
  • 无状态会话管理

2. 环境准备

安装所需依赖库(推荐使用虚拟环境):

pip install fastapi==0.95.2 python-jose[cryptography]==3.3.0 passlib==1.7.4 bcrypt==4.0.1 uvicorn==0.22.0

3. 生成 JWT 令牌

3.1 核心配置类

from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel # 安全配置
SECRET_KEY = "your-secret-key-here" # 生产环境应从环境变量获取
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30 # 密码哈希配置
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") class Token(BaseModel):
access_token: str
token_type: str class TokenData(BaseModel):
username: str | None = None

3.2 令牌生成函数

def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt

3.3 登录接口实现

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm router = APIRouter() @router.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}

4. JWT 验证机制

4.1 令牌验证中间件

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user

4.2 受保护路由示例

@router.get("/users/me/")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user

5. 令牌刷新机制

实现令牌刷新接口:

@router.post("/refresh")
async def refresh_token(refresh_token: str):
try:
payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if username is None:
raise HTTPException(status_code=400, detail="Invalid token") # 检查用户是否存在(需要实现具体数据库查询)
user = get_user(username)
if not user:
raise HTTPException(status_code=404, detail="User not found") new_token = create_access_token(data={"sub": user.username})
return {"access_token": new_token} except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")

课后Quiz

  1. 为什么JWT需要设置过期时间?

    A) 减少服务器内存占用

    B) 防止令牌被长期盗用

    C) 提高加密强度

    D) 简化开发流程

  2. 以下哪个做法会破坏JWT的安全性?

    A) 使用HTTPS传输令牌

    B) 将敏感数据存储在Payload中

    C) 定期轮换加密密钥

    D) 验证签名算法

  3. 如何处理令牌过期的情况?

    A) 返回500错误

    B) 要求用户重新登录

    C) 使用refresh token获取新令牌

    D) 自动延长过期时间

答案:

  1. B - 设置过期时间可限制令牌有效期,降低被盗用后的风险
  2. B - Payload内容虽然被加密但可被解码,不应存储敏感信息
  3. C - 最佳实践是通过refresh token机制更新访问令牌

常见报错解决方案

  1. 401 Unauthorized: Could not validate credentials

    • 原因:无效的令牌格式或签名不匹配
    • 解决:检查请求头的Bearer token格式,验证密钥一致性
  2. 422 Validation Error

    • 原因:请求体与Pydantic模型不匹配
    • 预防:使用精确的模型定义,添加字段验证规则
  3. 500 Internal Server Error: JWTError

    • 原因:令牌解码失败或算法不匹配
    • 处理:捕获JWTError异常,返回401状态码
    • 检查:确保服务端使用的算法与生成令牌时一致
  4. AttributeError: 'NoneType' has no attribute 'username'

    • 原因:数据库查询返回空值
    • 修复:在数据库查询后添加空值检查
    • 优化:使用Optional类型注解和空值处理

最佳实践建议:

  1. 生产环境使用RSA非对称加密(RS256算法)
  2. 将密钥存储在环境变量或密钥管理服务中
  3. 设置合理的令牌有效期(通常访问令牌15分钟,刷新令牌7天)
  4. 实现令牌撤销清单(黑名单机制)

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:JWT令牌如何在FastAPI中实现安全又高效的生成与验证? | cmdragon's Blog

往期文章归档:

JWT令牌如何在FastAPI中实现安全又高效的生成与验证?的更多相关文章

  1. 如何在IJ中使用Jaxb2通过xml定义生成对应的Java Entity类的文件

    #0. 准备要转换的xml文件,在Project视界中,右击这个xml文件,在弹出的菜单上选择“Generate XSD schema from XML File...”, 按默认设置生成xsd文件. ...

  2. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  3. spring security oauth2搭建resource-server demo及token改造成JWT令牌

    我们在上文讲了如何在spring security的环境中搭建基于oauth2协议的认证中心demo:https://www.cnblogs.com/process-h/p/15688971.html ...

  4. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  5. 第39章 引用令牌 - Identity Server 4 中文文档(v1.0.0)

    访问令牌有两种形式 - 自包含或引用. JWT令牌将是一个自包含的访问令牌 - 它是一个带有声明和过期的受保护数据结构.一旦API了解了密钥材料,它就可以验证自包含的令牌,而无需与发行者进行通信.这使 ...

  6. 阶段5 3.微服务项目【学成在线】_day18 用户授权_03-方法授权-jwt令牌包含权限

    修改认证服务的UserDetailServiceImpl类,下边的代码中 permissionList列表中存放了用户的权限, 并且将权限标识按照中间使用逗号分隔的语法组成一个字符串,最终提供给Spr ...

  7. 什么是JWT令牌认证?

    当下,JWT(JSON Web Token)令牌认证已经变得越来越流行.本文主要介绍JWT令牌认证与传统的Session会话认证机制的区别. 为什么需要认证? HTTP是一种无状态协议,那就意味着当前 ...

  8. OAuth + Security - 3 - JWT令牌

    为什么使用JWT令牌 在上面的资源服务器中,通过配置,我们了解到,当我们拿着token去获取资源时,程序会先去调用远程认证服务器的端点去验证解析token,或者在本地解析校验token,这样毫无疑问, ...

  9. 畅购商城(八):微服务网关和JWT令牌

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 畅购商城(一):环境搭建 畅购商 ...

  10. Jwt令牌创建

    添加依赖 <dependencies> <!-- jwt --> <dependency> <groupId>io.jsonwebtoken</g ...

随机推荐

  1. 从零开始开发一个 MCP Server!

    大家好!我是韩老师. 最近,在 AI 开发领域,MCP (Model Context Protocol) 是越来越火了! 前几天,我我也开发了一款 Code Runner MCP Server: Co ...

  2. 【Linux】3.8 Linux磁盘分区、挂载

    Linux磁盘分区.挂载 1. 分区方式 mbr分区 最多支持四个主分区 系统只能安装在主分区 扩展分区要占一个主分区 MBR最大只支持2TB,但拥有最好的兼容性 gpt分区 支持无限多个主分区(但操 ...

  3. SQLite 爬坑记录之无法设置自增约束

    场景重现 SQLite在设置自增约束(Autoincrement)的时候出现无法设置的情况: 问题原因 ... 解决办法 ...

  4. firedac的性能

    应该说,目前10.3的方方面面基本正常的坑基本填好了.因此综合考虑还是用datasanp+firedac框架操练. ================================ 数据量2w行,字段 ...

  5. Graph4Stream:基于图的流计算加速

    作者:汪煜 之前在「姊妹篇」<Stream4Graph:动态图上的增量计算>中,向大家介绍了在图计算技术中引入增量计算能力「图+流」,GeaFlow流图计算相比Spark GraphX取得 ...

  6. 物理机burpsuite抓包虚拟机以及Chrome导入burp证书

    记录物理机的burpsuite抓包虚拟机谷歌浏览器和遇到的问题总结 从别的地方搬家过来的,图片有水印懒得改了就这样吧,或者改天抹了( 打开虚拟机,网络适配器选择NAT 打开主机的burpsuite,点 ...

  7. 微信接龙转Excel

    1.新建Excel表格 2.将微信接龙信息复制至表格 3.选择列 4.选择[数据]->[分列] 5.选择[分隔符号]->[下一步] 6.选择[分隔符号]->[下一步] 这里以[空格] ...

  8. 记一次 .NET某旅行社酒店管理系统 卡死分析

    一:背景 1. 讲故事 年初有位朋友找到我,说他们的管理系统不响应了,让我帮忙看下到底咋回事? 手上也有dump,那就来分析吧. 二:为什么没有响应 1. 线程池队列有积压吗? 朋友的系统是一个web ...

  9. 适用于LixtBox的,开启UI虚拟化时,某些时候需要定位到还没加载的项,比如自动选中某项,视图自动移过去等等

    1 /// <summary> 2 /// 将指定父级的下级索引元素,显示在视野下,使其可见 3 /// </summary> 4 /// <param name=&qu ...

  10. NOIP集训 P11071 「QMSOI R1」 Distorted Fate 题解

    对本题的评价:有思维含量的线段树好题.曲子好听,曲绘好看,曲师人品好,谱子写得好,鸠好看 题解: P11071 「QMSOI R1」 Distorted Fate 给定一个长度为 \(n\) 的数组 ...