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:
tags:
扫描二维码
关注或者微信搜一搜:编程智域 前端至全栈交流与成长
探索数千个预构建的 AI 应用,开启你的下一个伟大创意:https://tools.cmdragon.cn/
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在双方之间安全地传递声明信息。它由三部分组成:
JWT 在 FastAPI 中的典型应用场景:
安装所需依赖库(推荐使用虚拟环境):
pip install fastapi==0.95.2 python-jose[cryptography]==3.3.0 passlib==1.7.4 bcrypt==4.0.1 uvicorn==0.22.0
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
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
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"}
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
@router.get("/users/me/")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
实现令牌刷新接口:
@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")
为什么JWT需要设置过期时间?
A) 减少服务器内存占用
B) 防止令牌被长期盗用
C) 提高加密强度
D) 简化开发流程
以下哪个做法会破坏JWT的安全性?
A) 使用HTTPS传输令牌
B) 将敏感数据存储在Payload中
C) 定期轮换加密密钥
D) 验证签名算法
如何处理令牌过期的情况?
A) 返回500错误
B) 要求用户重新登录
C) 使用refresh token获取新令牌
D) 自动延长过期时间
答案:
401 Unauthorized: Could not validate credentials
422 Validation Error
500 Internal Server Error: JWTError
AttributeError: 'NoneType' has no attribute 'username'
最佳实践建议:
余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长
,阅读完整的文章:JWT令牌如何在FastAPI中实现安全又高效的生成与验证? | cmdragon's Blog
参与评论
手机查看
返回顶部