安全
中间件
跨域资源共享
中间件
中间件是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应返回之前工作
- 接收应用的每一个请求,可对请求做一些事情,并通过路径操作将请求传递给应用的其他部分
- 通过路径操作获取应用的响应,并对响应做一些事情后将响应返回
- 如果使用了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
- 中间件参数接收参数request和call_next函数
- call_next函数将接收 request 作为参数,将 request 传递给相应的 路径操作
- 然后它将返回由相应的路径操作生成的 response,可以在返回 response 前进一步修改它
添加ASGI中间件
- 使用
app.add_middleware()
:接收一个中间件类作为第一参数和其他关键字参数
- HTTPSRedirectMiddleware:强制所有的请求必须是https/wss
- TrustedHostMiddleware:强制所有的请求必须在header中设置了host,防止HTTP Host Header攻击。使用方式如
app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"])
,其中allowed_hosts表示被允许的host列表,也可设置为[*]
表示所有的host - GZipMiddleware:处理任何在 Accept-Encoding 标头中包含“ GZip”的请求的 GZip 响应
- 更多可参考官方文档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