在FastAPI中已经内置了Starlette大量的middleware中间件,这些中间件可以初步用于OAuth2、CORS、Gzip等功能的实现。下面我们对这些常用中间件的使用进行详细的说明。
在一个FastAPI程序中,可以通过add_middleware引入多个中间件,这时就会出现执行顺序的问题。FastAPI遵循后进先执行的原则,参考下面的例子:
main.py
import uvicorn as uvicorn
from fastapi import FastAPI
from fapi.middlewares.multi_middleware import MutilAMiddleware, MutilBMiddleware
app = FastAPI()
app.add_middleware(MutilAMiddleware, assigned_number=1)
app.add_middleware(MutilBMiddleware, assigned_number=2)
@app.get("/")
async def index():
print("'index' router executed!")
return "test middleware"
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8088, reload=True)
multi_middleware.py
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
class MutilAMiddleware(BaseHTTPMiddleware):
def __init__(self, app, assigned_number):
super().__init__(app)
self.assigned_number = assigned_number
async def dispatch(self, request: Request, call_next):
print(f"{self.assigned_number}:'A' middleware executed!")
response = await call_next(request)
return response
class MutilBMiddleware(BaseHTTPMiddleware):
def __init__(self, app, assigned_number):
super().__init__(app)
self.assigned_number = assigned_number
async def dispatch(self, request: Request, call_next):
print(f"{self.assigned_number}:'B' middleware executed!")
response = await call_next(request)
return response
FastAPI借用了Starlette提供的内置中间件,包括:
SessionMiddleware:提供了基于cookie的HTTP会话管理功能。
import uvicorn as uvicorn
from fastapi import FastAPI
from starlette.middleware.sessions import SessionMiddleware
from starlette.requests import Request
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="middleware_secret_key")
@app.get("/set_session")
async def set_session(request: Request):
request.session["session_data"] = "some session data"
return 'set session data success!'
@app.get("/read_session")
async def read_session(request: Request):
return f'session data is: {request.session.get("session_data")}'
if __name__ == '__main__':
uvicorn.run(app="main:app", port=8088, reload=True)
SessionMiddleware中间件有如下配置参数:
secret_key - 随机字符串作为secret_key
session_cookie - cookie名称,默认‘session’
max_age - 会话过期时间,以秒为单位。默认为2周。如果设置为None,则cookie将持续存在,直到浏览器会话结束。
same_site - 标志阻止浏览器在跨站请求中发送会话cookie。默认为 ‘lax’。
https_only - 应设置安全标志(只能与HTTPS一起使用)。默认为False。
CORSMiddleware:提供跨域资源共享支持
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"https://test.foxtells.com",
"http://test.foxtells.com",
"http://localhost",
"http://localhost:8088",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def index():
return "test middleware"
CORSMiddleware中间件有如下配置参数:
allow_origins - 允许跨域请求的域名列表,例如 [‘https://example.org’, ‘https://www.example.org’] 或者 [‘*’]。
allow_origin_regex - 允许跨域请求的域名正则表达式,例如 ‘https://.*.example.org’。
allow_methods - 允许跨域请求的HTTP方法列表,默认为[‘GET’],[‘*’] 表示允许所有HTTP方法。
allow_headers - 跨域请求支持的HTTP头信息列表。[‘*’] 表示允许所有头信息。Accept, Accept-Language, Content-Language 和 Content-Type头信息默认全都支持。
allow_credentials - 表示在跨域请求时是否支持cookie,默认为False。
expose_headers - 表示对浏览器可见的返回结果头信息,默认为[]。
max_age - 浏览器缓存CORS返回结果的最大时长,默认为600(单位秒)。
HTTPSRedirectMiddleware:强制所有的请求使用http或者wss协议
from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
app.add_middleware(HTTPSRedirectMiddleware)
@app.get("/")
async def index():
return "test middleware"
TrustedHostMiddleware:强制所有的请求来自于可信Host,为了防止HTTP Host的头部攻击
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
app.add_middleware(
TrustedHostMiddleware, allowed_hosts=["foxtells.com", "*.foxtells.com"]
)
@app.get("/")
async def index():
return "test middleware"
GZipMiddleware:对内容进行GZip压缩
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=1000)
@app.get("/")
async def index():
return "some very big size content"
CORSMiddleware中间件有如下配置参数:
minimum_size - 当返回结果大小小于指定值时不启用压缩。(单位为字节,默认值为500)
CSRFMiddleware:用于防御CSRF攻击的中间件。此中间件实现了双提交Cookie模式,即首先设置一个cookie,然后将其与HTTP头x-csrftoken进行比较。
安装中间件:
pip install starlette-csrf
基本使用:
from fastapi import FastAPI
from starlette_csrf import CSRFMiddleware
app = FastAPI()
app.add_middleware(CSRFMiddleware, secret="__CHANGE_ME__")
@app.get("/")
async def index():
return "test middleware"
CSRFMiddleware中间件有如下配置参数:
secret (str) - 用于签名CSRF令牌值的密码。
required_urls(可选[List[re.Pattern]] - None) - 始终执行CSRF检查的URL正则表达式列表。
exempt_urls(可选[List[re.Pattern]] - None)- 跳过CSRF检查的URL正则表达式列表。sensitive_cookies (Set[str] - None) - 如果在请求中存在,应触发CSRF检查的cookie名称集合。如果此参数为None,即默认值,将始终执行CSRF。
safe_methods (Set[str] - {“GET”, “HEAD”, “OPTIONS”, “TRACE”}) - 不需要CSRF检查的HTTP方法。
cookie_name (str - csrftoken) - cookie的名称。
cookie_path (str - /) - cookie的路径。
cookie_domain (可选[str] - None) - cookie的域。如果您的前端和API位于不同的子域中,请确保使用您的根域设置此参数,以允许您的前端子域在JavaScript端读取cookie。
cookie_secure (bool - False) - 是否仅通过SSL请求将cookie发送到服务器。
cookie_samesite (str - lax) - cookie的Samesite策略。
header_name (str - x-csrftoken) - 设置CSRF令牌的header名称。
通过继承CSRFMiddleware,可以自定义错误Response:
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
from starlette_csrf import CSRFMiddleware
class CustomResponseCSRFMiddleware(CSRFMiddleware):
def _get_error_response(self, request: Request) -> Response:
return JSONResponse(
content={"code": "CSRF_ERROR"}, status_code=403
)