文章目录
-
- 你的APP要用户反复登录?密码传来传去?FastAPI+JWT实战,一个令牌全打通,安全与体验兼得,代码直接抄
-
- 为什么我的 API 需要 JWT?
- JWT 究竟是什么?它真的安全吗?
-
-
- JWT 究竟是什么?
- JWT 的三段式结构
- JWT 的工作流程:一次登录,处处认证
-
- 实战:基于 FastAPI 的 JWT 完整实现
-
-
- 01、安装依赖与配置密钥
- 02、核心方法——生成JWT令牌
- 03、创建登录接口,返回令牌
- 04、登录接口测试
- 05、JWT 令牌验证,保护授权接口
-
- JWT 带来的变革
- 关于 FastAPI 的其他疑问
你的APP要用户反复登录?密码传来传去?FastAPI+JWT实战,一个令牌全打通,安全与体验兼得,代码直接抄

深夜,你又收到一条用户投诉:“我在你们App上刚买完东西,跳到客服页面为什么又要我登录一次?!”
你盯着屏幕,赶紧回复 “抱歉” 。
心里一阵苦笑:还不是因为那两个老系统互不认账,用户状态根本同步不了。更让你心虚的是,有些接口还有用基础认证,密码在请求里 “裸奔”……
这不是你一个人的问题。当应用拆分成多个服务,“如何让用户一路畅通,又能保证安全?” 成了系统架构中最磨人的痛点之一。
今天,我就带你用 FastAPI + JWT,打造一把“万能密钥”。从此,用户一次登录,一路通行。
为什么我的 API 需要 JWT?
试想一下,用户在你的App上刚登录完,当跳转到后台管理页面,又要输一次密码……。这种体验,用户会不会扭头就走?
这就是传统身份验证的痛点:
JWT 的救赎之道
而 JWT 的出现,正是为了解决这一核心冲突。它就像一张数字通行证,用户只需登录一次,即可在多个关联服务间畅通无阻,系统既能识别用户身份,又无需保存会话状态。
JWT 究竟是什么?它真的安全吗?
参考:https://www.jwt.io/introduction
JWT 究竟是什么?
JWT(JSON Web Token)就是用户登录成功后,后端返回的 “加密电子身份证”—— 前端存起来,后续请求核心接口时带上,后端校验 token 有效就放行。
JWT 的三段式结构
先来看一个 JWT 令牌示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp–QV30
这个 JWT 令牌看着像一串天书,它实际上由三部分组成,用点(.)分隔:
{Header}.{Payload}.{Signature}
Header(头部):指明令牌类型和签名算法。
{
"alg": "HS256",
"typ": "JWT"
}
然后,这个 JSON 经Base64编码为 Base64Url,形成JWT的第一部分。
Payload(载荷):包含声明数据。声明有三种类型:注册声明、公共声明、私有声明。
注册声明:预定义字段,非强制但推荐。如iss(签发者)、exp(过期时间)
公共声明:自定义字段,需避免冲突
私有声明:双方约定的自定义字段
示例:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
Signature(签名):签名是JWT的安全核心。
使用 HMAC SHA256 算法,签名方式如下:
# 伪代码演示签名过程
signature = HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
签名确保令牌未被篡改,因为只有服务器拥有密钥,客户端无法伪造有效签名。
JWT 的工作流程:一次登录,处处认证
实战:基于 FastAPI 的 JWT 完整实现
01、安装依赖与配置密钥
安装依赖包
pip install "python-jose[cryptography]" -i https://pypi.tuna.tsinghua.edu.cn/simple
生成一个高强度的密钥(切勿使用简单字符串):
(.venv) wangerge_notes: TodoApp$ openssl rand -hex 32
eec7f9b96330e64eaac29ad7c95154cff3addaea90239c262b3f9287e678f6d3
在配置文件中设置:
# auth.py
SECRET_KEY = "eec7f9b96330e64eaac29ad7c95154cff3addaea90239c262b3f9287e678f6d3"
ALGORITHM = "HS256"
02、核心方法——生成JWT令牌
# auth.py
def create_access_token(
username: str, user_id: int, expires_delta: timedelta):
# 载荷:仅存非敏感信息
encode = {"sub": username, "id": user_id}
# 过期时间(修正:时区正确,避免过期异常)
expire = datetime.now(timezone.utc) + expires_delta
encode.update({"exp": expire})
# 编码生成token
return jwt.encode(encode, SECRET_KEY, algorithm=ALGORITHM)
03、创建登录接口,返回令牌
# 定义响应模型(确保返回格式统一,避免验证错误)
class Token(BaseModel):
access_token: str
token_type: str
# 验证用户
def authenticate_user(username: str, password: str, db):
user = db.query(Users).filter(Users.username == username).first()
if not user:
return False
if not bcrypt_context.verify(password, user.hashed_password):
return False
return user
@router.post("/token", response_model=Token)
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
db: Annotated[Session, Depends(get_db)]
):
# 校验用户名和密码
user = authenticate_user(form_data.username, form_data.password, db)
# 检验失败,抛出异常
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate user.")
# 生成token
token = create_access_token(user.username, user.id, timedelta(minutes=20))
return {"access_token": access_token, "token_type": "bearer"}
04、登录接口测试
切回浏览器 Swagger UI 页面,刷新页面,找到 POST /token 接口,给传入 username=wangerge, password=test1234。这个用户名和密码是数据库里面的。
执行请求,返回响应码 200,响应体如下:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YW5nZXJnZSIsImlkIjoxLCJleHAiOjE3NjgxMzI0NTJ9.eiUqiVl8GHQx_bG61UvAzvAuuODInk5Szz5yPT5zkZs",
"token_type": "bearer"
}
此时,客户端传入的用户名和密码验证通过,返回加密 token。
再次切回浏览器 Swagger UI 页面,刷新页面,找到 POST /token 接口,给传入 username=wangerge, password=test。(传入一个错误的密码)
执行请求,返回响应码 401,响应体如下:
{
"detail": "Could not validate user."
}
此时,客户端传入的用户名和密码验证失败,返回异常信息。
至此,当客户端通过浏览器给服务器传入一个正确的用户名和密码后,服务器能正确的生成 JWT 令牌信息,并返回给客户端。
05、JWT 令牌验证,保护授权接口
添加函数 get_current_user,解码并验证 JWT 令牌。
from datetime import timedelta, datetime, timezone
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
auth2_bearer = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(
token: Annotated[str, Depends(auth2_bearer)]):
try:
# 检查令牌的真实性。
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
user_id: int = payload.get("id")
if username is None or user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate user.")
return {"username": username, "id": user_id}
except JWTError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate user.")
在上面代码中,我们解码 token ,得出用户名和用户 ID,并结构化返回。
下面给授权接口添加用户验证。
来到 todos.py 文件,导入 get_current_user 函数
from .auth import get_current_user
添加 user_dependency 依赖注入
user_dependency = Annotated[dict, Depends(get_current_user)]
来到 GET /todo/ 接口处,现在,要求这个接口必须要获取到用户登录信息后,才可以正常请求。
给 read_all 方法,添加 user: user_dependency 参数,并添加 user 判断。代码如下:
@router.get("/todo")
async def read_all(user: user_dependency, db: db_dependency):
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Failed Authentication")
return db.query(models.Todos).all()
切回浏览器 Swagger UI 页面,刷新页面,找到 GET /todo/ 接口,执行请求。
返回响应码 401,响应体:"detail": "Not authenticated"
这表示需要一个用户认证,才能执行 API 请求,这就是用户验证。
我们找到 Swagger UI 页面 POST /todo 接口,在列表栏最右边,可以找到一个小锁的图标。如下图:

点击打开它,提示我们需要输入用户名和密码。
输入 username=“wangerge” password=“test1234” 点击 “Authorize” 按钮提交。
认证成功,结果如下图:

现在,用户已经登录成功了。重新执行 GET /todo/ 接口请求。
服务器返回响应码 200。接口请求成功了。
JWT 带来的变革
通过以上实验,我们解决了开篇提到的痛点:
避坑指南:
JWT 在 API 身份验证与授权的道路上,无疑是一把锋利而优雅的瑞士军刀。
想要获取本章完整代码,请在评论区回复 【FastAPI】,代码直接复制就能跑。
关于 FastAPI 的其他疑问
FastAPI极速上手:从API到全栈,高薪后端必备技能
10分钟用Python搭个接口,还能自动生成文档?
3分钟搞定Python虚拟环境和FastAPI安装
FastAPI实战:3步搞定增删改查,你的第一个完整API来了!
别再堆if-else验参数了!FastAPI自带的参数验证器,至少省一半调试时间
3分钟搞定FastAPI的数据库设置,把数据存储玩明白,复制代码就能用
10分钟搞定FastAPI中“数据库连接管理、参数校验、文档维护”三大核心难题,让新手也能轻松地写出可落地的API
“警惕!FastAPI接口一夜「消失」” 95%程序员靠这招自救:我的路由分离血泪史
相关内容我都给大家做好了,感兴趣的朋友来「我的主页」找一找,直接就可以看到。
关注我,每天分享「Python」、「职场」有趣干货,千万不要错过!
网硕互联帮助中心






评论前必须登录!
注册