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. DBeaver连接mysql时,报错Public Key Retrieval is not allowed

    解决 在新建连接的时候,驱动属性里设置 allowPublicKeyRetrieval 的值为 true.

  2. Centos下安装php mysql pdo以及gd扩展

    pdo扩展安装: yum install php-pdo pdomysql扩展安装: yum install php-pdo_mysql gd库扩展安装: yum install php-gd 安装后 ...

  3. JOKER 低代码平台 20250313 重磅更新:全方位升级,解锁开发新体验

    JOKER 低代码平台于 2025 年 3 月 13 日迎来了一次全面且深度的升级.本次更新聚焦前端交互.服务端功能以及通用操作等多个关键领域,致力于打造更卓越的开发环境,为开发者们带来更加高效.稳定 ...

  4. 搭建docker swarm集群实现负载均衡

    Swarm简介:Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源.Swarm ...

  5. 继承中构造方法访问特点--java 进阶day01

    1.子类不可以继承父类的构造方法 构造方法的名称必须与类名一致,上图中类名是Zi,而构造方法名是Fu,肯定不行 2.子类在初始化之前,需要对父类初始化 子类在初始化的过程中,很有可能会调用到父类的数据 ...

  6. 【单片机】滑稽AT89C52表情实现

    [单片机]滑稽AT89C52表情实现 零.原因 在群里看到了这样一个表情: 这是用51做的,刚好开发板上有8个小灯,想实现一下. 一.代码 新建工程,写入如下代码: #include<reg52 ...

  7. Kratos 下载与安装

    前置条件 请确保已经安装好 go git protoc 然后获取 kratos 工具 go get -u github.com/go-kratos/kratos/tool/kratos 验证是否安装成 ...

  8. Microsoft.NETCore.App 版本不一致导致的运行失败

    场景重现 今天新建了一个 ASP.NET Core 的项目, 通过 Web Deploy 顺利发布到IIS上后, 但访问时出现如下异常: 异常原因 通过手动执行dotnet命令发现运行框架版本不一致? ...

  9. dxSpreadSheet的报表demo-关于设计报表模板的Datagroup问题

    看随机的报表DEMO,主从表也好,数据分组也好.呈现的非常到位. 问题:可是自己在实现数据分组时,一旦设定分组字段就出现了混乱的数据记录. 问题的原因: 看一下一个报表页面设计时需要理清的概念. 页头 ...

  10. JSON Objects Framework(1)

    学习datasnap,json必须掌握.用自身的JSON,就必须熟悉JSON Objects Framework.其中tostring和value区别就是一个坑. The JSON objects f ...