在当今的 Web 开发中,保护 API 不受未授权访问至关重要。JWT(JSON Web Token)是一种流行的用于身份验证的开放标准,它允许用户在客户端和服务器之间安全地传输信息。FastAPI 是一个现代、快速的 Web 框架,用于构建 API,它具有许多优秀特性,如自动文档生成功能和依赖注入系统。在本文中,我们将探讨如何在 FastAPI 中实现 JWT 身份验证。
JWT 是一种紧凑、自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。每个令牌由三部分组成,它们之间用点(.)分隔:
首先确保安装了 FastAPI 和 Uvicorn。可以使用以下命令安装:
pip install fastapi uvicorn
然后安装 Python_jwt 和 pyjwt 库:
pip install python-jwt pyjwt
在代码中导入 FastAPI 和其他必要的库:
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
import jwt
from jwt import PyJWTError
from datetime import datetime, timedelta
from typing import Optional
from pydantic import BaseModel
SECRET_KEY = "your-secret-key" # 在实际应用中使用更安全的方法生成和存储密钥
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
fake_users_db = {
"john": {
"username": "john",
"password": "secret",
"email": "[email protected]",
}
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def verify_password(plain_password, hashed_password):
return plain_password == hashed_password # 实际应用中使用更安全的哈希方法
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return user_dict
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user['password']):
return False
return user
def create_access_token(data: dict, expires_delta: Optional[timedelta] = 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
app = FastAPI()
@app.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"}
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 PyJWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
启动应用:
uvicorn main:app --reload
打开浏览器访问 http://localhost:8000/docs
,使用 Swagger UI 测试 API。通过 /token
端点获取访问令牌,然后使用该令牌访问 /users/me
端点。
通过在 FastAPI 中实现 JWT 身份验证,可以为你的 API 提供一种安全且无状态的身份验证机制。这种方式适用于各种规模的应用,能够有效保护 API 不受未授权访问。在实际应用中,请确保使用安全的方法生成和存储密钥,并采用更健壮的密码哈希算法来提高安全性。