跳到主要内容

FastAPI 用户认证(OAuth2 和 JWT 方式)

本篇教程将带你了解 FastAPI 中实现用户认证(Authentication)的基础方法,包括使用 OAuth2 密码模式、JWT(JSON Web Token)进行令牌签发和验证,以及如何保护需要登录访问的接口。你将学会如何构建一个基本的登录系统,为后续权限控制打好基础。

用户认证 vs. 用户授权

在开始之前,先简单区分两个概念:

概念说明
认证(Authentication)判断你是谁,即“你是否已登录”
授权(Authorization)判断你是否有权限做某事,例如“你是否可以删除某条记录”

本节聚焦在用户认证

OAuth2 密码模式 + JWT 简介

FastAPI 支持 OAuth2 多种认证方式,这里我们选择最常见也最易上手的一种:OAuth2 密码模式 + JWT 令牌

它的基本流程如下:

  1. 用户通过用户名和密码登录;
  2. 后端验证通过后,返回一个签名的 JWT access token
  3. 前端保存该 token,并在后续请求中通过 Authorization: Bearer <token> 携带;
  4. 后端验证 token 后允许访问受保护资源。

🔐 OAuth2 是什么?

OAuth2 是一种授权协议,用于让第三方应用安全地访问资源。它广泛用于“登录”或“授权”场景。

在实际开发中,OAuth2 有多种使用方式(称为“授权模式”),而我们常用的这种“用户输入用户名密码获得 access token”的方式被称为 OAuth2 密码模式(Password Grant Type)

它的工作流程如下:

  1. 用户填写用户名和密码,发送到后端 /token 接口;
  2. 后端验证成功后,生成一个 access_token
  3. 前端保存该 token,并在之后访问需要登录的接口时携带它。

你可以把 token 理解为一张临时“通行证”。

🛡️ JWT 是什么?

JWT(全称:JSON Web Token)是用于身份验证的一种令牌格式

JWT 是一串由三部分组成的字符串,长这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJhbGljZSIsImV4cCI6MTY4M...
zRyLeKLgdxCgNyjgm5DndS49ArSl94uwac...

每个 JWT 包含三部分:

部分说明
Header(头部)指明使用的签名算法(如 HS256)
Payload(载荷)存放用户信息(如用户名、过期时间)
Signature(签名)由密钥加密生成,用于防篡改验证

JWT 的好处是:

  • 结构清晰,前端和后端都可以解析;
  • 可以不用访问数据库,仅靠 token 判断身份(无状态);
  • 签名防篡改,更安全。

FastAPI 的推荐做法是:登录成功后返回一个 JWT 令牌,前端拿到后就可以用它访问后端的受保护接口。

OAuth2 和 JWT 是什么关系?

OAuth2 规定了“认证流程”,JWT 是实现 token 的一种方式。

换句话说:OAuth2 是流程规范,JWT 是令牌格式。你可以用 OAuth2 的登录流程返回任意类型的 token,但 JWT 是最常见也最推荐的格式。

准备工作

依赖包安装

pip install "python-jose[cryptography]" passlib[bcrypt]
  • python-jose:用于生成和验证 JWT;
  • passlib[bcrypt]:用于安全地哈希和验证密码。

示例项目结构

.
├── main.py # FastAPI 主程序
├── auth.py # 认证逻辑模块(签发、验证 JWT)
└── users.py # 模拟用户数据库与密码校验

完整代码示例

1. 模拟用户数据和密码校验(users.py)

users.py
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 模拟数据库中的用户
fake_users_db = {
"alice": {
"username": "alice",
"hashed_password": pwd_context.hash("secret"),
}
}

def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)

def get_user(username: str):
return fake_users_db.get(username)

2. JWT 相关逻辑(auth.py)

auth.py
from datetime import datetime, timedelta
from jose import JWTError, jwt

# 密钥和算法(生产环境需保密)
SECRET_KEY = "mysecretkey123"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

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

def decode_access_token(token: str):
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])

3. 主程序(main.py)

main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from users import get_user, verify_password
from auth import create_access_token, decode_access_token

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")

# 登录接口:返回 access_token
@app.post("/token")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = get_user(form_data.username)
if not user or not verify_password(form_data.password, user["hashed_password"]):
raise HTTPException(status_code=401, detail="用户名或密码错误")

access_token = create_access_token(data={"sub": user["username"]})
return {"access_token": access_token, "token_type": "bearer"}

# 受保护接口:必须携带有效 token 才能访问
@app.get("/me")
def read_users_me(token: str = Depends(oauth2_scheme)):
try:
payload = decode_access_token(token)
username = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="无效的 token")
except Exception:
raise HTTPException(status_code=401, detail="无法验证 token")

return {"username": username}

请求示例

你可以使用 Postman、curl、或前端代码来测试:

获取 Token

curl -X POST "http://localhost:8000/token" -H "Content-Type: application/x-www-form-urlencoded" -d "username=alice&password=secret"

返回示例:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR...",
"token_type": "bearer"
}

使用 Token 访问受保护接口

curl -H "Authorization: Bearer <your_token_here>" http://localhost:8000/me

小提示

  • 可以将登录信息存入前端本地存储(localStorage 或 cookie)中;
  • 生产环境中应使用 HTTPS 传输 token;
  • 为支持刷新机制,可结合 refresh_token 设计。

小结

FastAPI 提供了优雅且现代的认证机制,结合 OAuth2 和 JWT 可以轻松构建安全的认证系统。你可以快速实现登录、令牌生成、用户信息读取等功能。接下来,你可以进一步探索权限控制、角色管理和 OAuth2 社交登录(如 GitHub、微信等)集成。

知心 MBTI 微信小程序
「知心MBTI」微信小程序,探索你的 MBTI 人格类型,发现潜能。微信扫码免费测试 🎉