FastAPI 与 JWT 身份验证:保护你的 API

一、引言

在当今的 Web 开发中,保护 API 不受未授权访问至关重要。JWT(JSON Web Token)是一种流行的用于身份验证的开放标准,它允许用户在客户端和服务器之间安全地传输信息。FastAPI 是一个现代、快速的 Web 框架,用于构建 API,它具有许多优秀特性,如自动文档生成功能和依赖注入系统。在本文中,我们将探讨如何在 FastAPI 中实现 JWT 身份验证。

二、什么是 JWT?

JWT 是一种紧凑、自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。每个令牌由三部分组成,它们之间用点(.)分隔:

  1. 头部(Header):包含令牌类型(通常是 JWT)和使用的签名算法,例如 HMAC SHA256 或 RSA。
  2. 载荷(Payload):包含声明,即关于实体(通常是用户)的某些信息,以及其他的额外信息。
  3. 签名(Signature):用于验证消息在传输过程中未被篡改。

三、为什么使用 JWT?

  • 无状态:服务器不需要在服务器端存储会话信息,减少了服务器的负载。
  • 可扩展:由于服务器不需要保存会话状态,因此更容易扩展到多个服务器。
  • 灵活性:可以在令牌中包含关于用户或会话的任何类型的信息。

四、在 FastAPI 中实现 JWT

1. 项目设置

首先确保安装了 FastAPI 和 Uvicorn。可以使用以下命令安装:

bash 复制代码
pip install fastapi uvicorn

然后安装 Python_jwt 和 pyjwt 库:

bash 复制代码
pip install python-jwt pyjwt

2. 导入必要的库

在代码中导入 FastAPI 和其他必要的库:

python 复制代码
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

3. 配置 JWT 密钥和算法

python 复制代码
SECRET_KEY = "your-secret-key"  # 在实际应用中使用更安全的方法生成和存储密钥
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

4. 创建用户模型和数据库模拟

python 复制代码
fake_users_db = {
    "john": {
        "username": "john",
        "password": "secret",
        "email": "john@example.com",
    }
}

class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    username: Optional[str] = None

5. 创建身份验证函数

python 复制代码
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

6. 创建 API 路由

python 复制代码
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

五、测试 API

启动应用:

bash 复制代码
uvicorn main:app --reload

打开浏览器访问 http://localhost:8000/docs,使用 Swagger UI 测试 API。通过 /token 端点获取访问令牌,然后使用该令牌访问 /users/me 端点。

六、总结

通过在 FastAPI 中实现 JWT 身份验证,可以为你的 API 提供一种安全且无状态的身份验证机制。这种方式适用于各种规模的应用,能够有效保护 API 不受未授权访问。在实际应用中,请确保使用安全的方法生成和存储密钥,并采用更健壮的密码哈希算法来提高安全性。

相关推荐
曲幽4 分钟前
FastAPI流式输出实战与避坑指南:让AI像人一样“边想边说”
python·ai·fastapi·web·stream·chat·async·generator·ollama
曲幽1 天前
不止于JWT:用FastAPI的Depends实现细粒度权限控制
python·fastapi·web·jwt·rbac·permission·depends·abac
曲幽2 天前
FastAPI分布式系统实战:拆解分布式系统中常见问题及解决方案
redis·python·fastapi·web·httpx·lock·asyncio
曲幽3 天前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
曲幽4 天前
FastAPI实战:打造本地文生图接口,ollama+diffusers让AI绘画更听话
python·fastapi·web·cors·diffusers·lcm·ollama·dreamshaper8·txt2img
曲幽5 天前
我用FastAPI接ollama大模型,差点被asyncio整崩溃(附对话窗口实战)
python·fastapi·web·async·httpx·asyncio·ollama
闲云一鹤6 天前
Python 入门(二)- 使用 FastAPI 快速生成后端 API 接口
python·fastapi
曲幽6 天前
FastAPI + Ollama 实战:搭一个能查天气的AI助手
python·ai·lora·torch·fastapi·web·model·ollama·weatherapi
DianSan_ERP7 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
呉師傅7 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑