安全
中间件
跨域资源共享

中间件

中间件是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应返回之前工作

  • 接收应用的每一个请求,可对请求做一些事情,并通过路径操作将请求传递给应用的其他部分
  • 通过路径操作获取应用的响应,并对响应做一些事情后将响应返回
  • 如果使用了yield依赖,依赖中的退出代码在执行中间件后执行
  • 如果使用了后台任务,后台任务也在执行中间件后执行

自定义中间件

  • 在函数的顶部使用装饰器 @app.middleware("http")
  • 如下例子是给响应添加自定义的X-Process-Time响应头
import time
import uvicorn

from fastapi import FastAPI, Request

app = FastAPI()


@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    print(1, "in middleware function...")
    response = await call_next(request)   # await
    process_time = time.time() - start_time
    print(3, process_time, "=========")
    response.headers["X-Process-Time"] = str(process_time)
    print(4, "response header added...")
    return response


@app.get("/items/{item_id}")
async def read_items(item_id: int):
    time.sleep(5)
    print(2, "in request function...")
    return {"item_id": item_id}


if __name__ == '__main__':
    uvicorn.run("main:app", reload=True)
##################控制台打印#################
1 in middleware function...
2 in request function...
3 5.003414154052734 =========
4 response header added...
INFO:     127.0.0.1:61985 - "GET /items/111 HTTP/1.1" 200 OK

postman访问http://127.0.0.1:8000/items/111并查看控制台打印和响应头是否有添加X-Process-Time

  1. 中间件参数接收参数request和call_next函数
  2. call_next函数将接收 request 作为参数,将 request 传递给相应的 路径操作
  3. 然后它将返回由相应的路径操作生成的 response,可以在返回 response 前进一步修改它

添加ASGI中间件

  • 使用app.add_middleware():接收一个中间件类作为第一参数和其他关键字参数
  1. HTTPSRedirectMiddleware:强制所有的请求必须是https/wss
  2. TrustedHostMiddleware:强制所有的请求必须在header中设置了host,防止HTTP Host Header攻击。使用方式如app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]),其中allowed_hosts表示被允许的host列表,也可设置为[*]表示所有的host
  3. GZipMiddleware:处理任何在 Accept-Encoding 标头中包含“ GZip”的请求的 GZip 响应
  4. 更多可参考官方文档Other middlewares

跨域资源共享

本节将介绍使用中间件处理跨域资源共享

CORS

百度百科:CORS(Cross-Origin Resource Sharing)即跨域资源共享(更准确地说是跨源资源共享)是一种允许当前域的资源被其他域的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求

  • 源(Origin)是协议protocol(http,https)、域domain(myapp.com,localhost,localhost.tiangolo.com)以及端口port(80、443、8080)的组合
# 这些都是不同源,它们使用了不同的协议或者端口
http://monkeyjerry.top
https://monkeyjerry.top
http://monkeyjerry.top:8080
  • 更多关于CORS可进一步阅读
  • 后端必须有一个允许的源列表,如使用通配符*声明这个列表,表示全部都是允许的(不包括所有涉及凭据的内容:像 Cookies 以及那些使用 Bearer 令牌的授权 headers 等),但最好显式地指定允许的源

CORSMiddleware

在 FastAPI 应用中使用 CORSMiddleware 配置

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
async def main():
    return {"message": "Hello World"}
  • allow_origins: 允许跨域请求的源列表list,可以使用 ['*']允许任何源。
  • allow_origin_regex :正则表达式字符串,匹配的源允许跨域请求。例如https://.*\.example\.org
  • allow_methods:允许跨域请求的 HTTP 方法列表list,默认为 ['GET'],可以使用 ['*']来允许所有方法
  • allow_headers:允许跨域请求的 HTTP 请求头列表list,默认为 [],可以使用 ['*']允许所有的请求头。Accept、Accept-Language、Content-Language 以及 Content-Type 请求头总是允许 CORS 请求
  • allow_credentials:指示跨域请求支持 cookies,默认是 False,设置为 True 时allow_origins 不能设定为['*'],必须指定源
  • expose_headers:指示可以被浏览器访问的响应头,默认为 []
  • max_age:设定浏览器缓存 CORS 响应的最长时间,单位为秒,默认为 600