以下是一个简单的FastAPI认证示例:
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext
from datetime import datetime, timedelta
from jose import JWTError, jwt
app = FastAPI()
# 定义一些常量
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# 定义密码哈希上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# 定义用户模型
class User:
def __init__(self, username: str, hashed_password: str):
self.username = username
self.hashed_password = hashed_password
# 假设这是一个数据库,存储了一些用户信息
users_db = {
"zeco": User("zeco", pwd_context.hash("password")),
"jane": User("jane", pwd_context.hash("123456")),
}
# 定义获取用户的函数
def get_user(username: str):
if username in users_db:
return users_db[username]
return None
# 定义验证密码的函数
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# 定义创建访问令牌的函数
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# 定义解析访问令牌的函数
def decode_access_token(access_token: str):
try:
payload = jwt.decode(access_token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if username is None:
raise JWTError
return username
except JWTError:
raise HTTPException(status_code=401, detail="Invalid access token")
# 定义OAuth2密码模式
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
# 定义获取访问令牌的路由
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = get_user(form_data.username)
if user is None:
raise HTTPException(status_code=401, detail="Invalid username or password")
if not verify_password(form_data.password, user.hashed_password):
raise HTTPException(status_code=401, detail="Invalid username or password")
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("/protected")
async def protected_route(access_token: str = Depends(oauth2_scheme)):
username = decode_access_token(access_token)
return {"message": f"Hello, {username}!"}
以上代码中,我们使用了Passlib库来创建密码哈希上下文,并使用JWT库来创建和解析访问令牌。我们定义了一个简单的用户模型和一个假的数据库来存储用户信息。在登录时,我们会验证用户名和密码,并创建一个访问令牌,该令牌将在指定的时间后过期。在需要认证的路由中,我们使用Depends装饰器来指定OAuth2密码模式,并在访问令牌验证通过后返回受保护的响应。