推荐答案
在 FastAPI 中,身份验证可以通过多种方式实现,最常见的方式是使用 OAuth2 和 JWT(JSON Web Tokens)。以下是一个使用 OAuth2 和 JWT 进行身份验证的示例:
// www.javascriptcn.com code example
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from pydantic import BaseModel
from datetime import datetime, timedelta
# 模拟用户数据库
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "fakehashedsecret",
"disabled": False,
}
}
# JWT 配置
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# OAuth2 密码模式
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# 用户模型
class User(BaseModel):
username: str
email: str | None = None
full_name: str | None = None
disabled: bool | None = None
# 用户数据库模型
class UserInDB(User):
hashed_password: str
# 创建 JWT 令牌
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
# 获取用户
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
# 验证用户
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not password == user.hashed_password:
return False
return user
# 获取当前用户
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
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username)
if user is None:
raise credentials_exception
return user
# 创建 FastAPI 应用
app = FastAPI()
# 登录路由
@app.post("/token")
async def login(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"}
# 受保护的路由
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user本题详细解读
1. OAuth2 和 JWT 简介
- OAuth2 是一种授权框架,允许用户授权第三方应用访问他们的资源,而不需要共享他们的密码。
- JWT 是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。JWT 通常用于身份验证和信息交换。
2. FastAPI 中的身份验证流程
- 用户登录:用户通过
/token路由提交用户名和密码。 - 验证用户:
authenticate_user函数验证用户是否存在以及密码是否正确。 - 生成 JWT:如果验证成功,
create_access_token函数生成一个 JWT 令牌,并将其返回给用户。 - 访问受保护的路由:用户在访问受保护的路由时,需要在请求头中携带 JWT 令牌。
- 验证 JWT:
get_current_user函数解码 JWT 令牌并验证其有效性,如果有效则返回当前用户信息。
3. 关键组件
- OAuth2PasswordBearer:用于定义 OAuth2 密码模式的依赖项,指定了获取令牌的 URL。
- JWT:用于生成和验证 JWT 令牌,确保数据的安全性和完整性。
- Depends:用于依赖注入,将身份验证逻辑与路由处理函数解耦。
4. 安全性
- SECRET_KEY:用于签名 JWT 令牌的密钥,应保持机密。
- ALGORITHM:指定 JWT 的签名算法,通常使用 HS256。
- ACCESS_TOKEN_EXPIRE_MINUTES:定义 JWT 令牌的有效期,过期后需要重新登录。
通过这种方式,FastAPI 提供了一种简单而强大的身份验证机制,适用于大多数 Web 应用场景。