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. C#语言碎片:Switch-Case语句字符串匹配

    Switch case语句在处理字符串类型匹配时候,case条件需要设置为静态常量或者一个具体的字符串: 因为工具类ToolHand.Name 为变量,所以编译不通过. 使用if语句来逐个判断: 看A ...

  2. mysql [ERR] 1273 - Unknown collation: 'utf8mb4_0900_ai_ci'

    这是因为当前数据库版本较高,需要更改一些参数 解决方法: 将sql文件中的 utf8mb4_0900_ai_ci替换为utf8_general_ci utf8mb4替换为utf8 再次运行SQL文件即 ...

  3. delphi 让执行程序不在任务栏显示

    Application.MainFormOnTaskbar := False; procedure TForm1.FormShow(Sender: TObject); begin ShowWindow ...

  4. dxTabbedMDIManager1关闭窗体

    procedure TfrmJianKongXinXi.FormClose(Sender: TObject; var Action: TCloseAction);begin Action:=caFre ...

  5. 【SpringCloud】SpringCloud Alibaba Sentinel实现熔断与限流

    SpringCloud Alibaba Sentinel实现熔断与限流 限流与降级 限流 blockHandler 降级 fallback 降级需要运行时出现异常才会触发,而限流一旦触发,你连运行的机 ...

  6. This APT has Super Cow Powers.

    在Debian/Ubuntu上,apt包管理器内嵌着一个彩蛋. 如果你在命令行界面输入 apt help 在最后一行能找到This APT has Super Cow Powers. 说明该apt具有 ...

  7. 调用 restful的api的方法

    var // myurl : string; tmpstr : String;// string; RespData :TStringStream; sendData : TStringList; j ...

  8. Python 类型检查与类型注解:mypy 与 typing 深度解析

    Python 类型检查与类型注解:mypy 与 typing 深度解析 在 Python 动态类型语言中,mypy 和 typing 是两个提升代码健壮性的核心工具.它们通过静态类型检查与类型注解,帮 ...

  9. Kylin-Server-V10-SP3物理机安装简要过程

    1.下载镜像 链接: https://eco.kylinos.cn/partners/mirror.html?class_id=1&query_key=V10 选择: 银河麒麟高级服务器操作系 ...

  10. CAS前后端分离解决方案

    CAS前后端分离解决方案 关于CSS服务器的搭建和整合SpringBoot参考:CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记 环境与需求 后端:springboot 前端: vu ...