1、新建一个 main.py 文件,把以下代码复制进去:
import secrets
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
from fastapi.security import HTTPBasic, HTTPBasicCredentials
# ==========================================
# 第一步:初始化 FastAPI,并彻底关闭默认的公开文档
# ==========================================
app = FastAPI(
docs_url=None, # 禁用默认的 /docs
redoc_url=None, # 禁用默认的 /redoc
openapi_url=None # 禁用默认的 /openapi.json
)
# 初始化 HTTP 基础认证工具(浏览器弹窗输入账号密码的那种)
security = HTTPBasic()
# ==========================================
# 第二步:编写一个“密码检查账号”的工具函数
# ==========================================
def authenticate_docs(credentials: HTTPBasicCredentials = Depends(security)):
“””
这个函数用来校验用户输入的账号和密码。
这里为了演示,直接把账号密码写死在代码里(实际开发中可以从环境变量或数据库读取)。
“””
# 定义你期望的正确账号和密码
CORRECT_USERNAME = “admin_user”
CORRECT_PASSWORD = “super_secret_password”
# secrets.compare_digest 可以安全地比较字符串,防止“计时攻击”
is_username_correct = secrets.compare_digest(credentials.username, CORRECT_USERNAME)
is_password_correct = secrets.compare_digest(credentials.password, CORRECT_PASSWORD)
# 如果账号或密码有任何一个不对,就弹出报错,提示需要认证
if not (is_username_correct and is_password_correct):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=”账号或密码错误”,
headers={“WWW-Authenticate”: “Basic”}, # 关键:这一行会让浏览器弹出账号密码输入框
)
return credentials.username
# ==========================================
# 第三步:手写受保护的 OpenAPI 数据接口
# ==========================================
# include_in_schema=False 的意思是:别让这个接口自己出现在文档里
@app.get(“/openapi.json”, include_in_schema=False)
async def get_open_api_endpoint(username: str = Depends(authenticate_docs)):
“””
只有通过了密码校验(authenticate_docs)的人,才能访问这个接口获取 API 的底层 JSON 数据。
“””
# 使用 FastAPI 自带的方法,动态生成你当前项目所有接口的结构数据
return get_openapi(
title=”我的加密 API 文档”,
version=”1.0.0″,
routes=app.routes
)
# ==========================================
# 第四步:手写受保护的 /docs 网页接口
# ==========================================
@app.get(“/docs”, include_in_schema=False)
async def protected_swagger_ui(username: str = Depends(authenticate_docs)):
“””
只有通过了密码校验的人,才能打开这个 /docs 网页。
“””
# 渲染并返回 Swagger UI 网页,并告诉网页:数据去 /openapi.json 拿(那个接口也是加密的)
return get_swagger_ui_html(
openapi_url=”/openapi.json”,
title=”安全 API 文档页面”
)
# ==========================================
# 示例:你自己的普通业务接口(会自动进入加密文档)
# ==========================================
@app.get(“/users”)
def get_users():
return [{“id”: 1, “name”: “张三”}]
@app.post(“/items”)
def create_item(name: str):
return {“status”: “success”, “item_name”: name}