概要
- FastAPIで設定したCORSの自動テスト方法
CORSについて
オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組み
FastAPIにおけるCORS設定方法
- FastAPI アプリケーションでは CORSMiddleware を使用して、CORSに関する設定を実施
- 詳細
CORSMiddlewareで設定可能な引数
引数 | 内容 | デフォルト |
---|---|---|
allow_origins | オリジン間リクエストを許可するオリジンのリスト | |
allow_origin_regex | オリジン間リクエストを許可するオリジンの正規表現文字列 | |
allow_methods | オリジン間リクエストで許可するHTTPメソッドのリスト | ['GET'] |
allow_headers | オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト CORSリクエストでは、 Accept 、 Accept-Language 、 Content-Language 、 Content-Type ヘッダーが常に許可されている |
[] |
allow_credentials | オリジン間リクエストでCookieをサポートする必要があることを示します | False |
expose_headers | ブラウザからアクセスできるようにするレスポンスヘッダーを示します | [] |
max_age | ブラウザがCORSレスポンスをキャッシュする最大時間を秒単位で設定します | 600 |
main.py
"""FastAPIのエントリーポイント."""
from typing import Dict
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
"""FastAPIのインスタンス"""
# 本来なら環境変数から設定できるようにしておくといい
origins = ["http://allowed.origin.com"]
# CORSのミドルウェアを設定
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def root() -> Dict[str, str]:
"""ルートパス.
Returns:
messeageを返却
"""
return {"message": "Hello World"}
CORSの設定に対する自動テスト方法
- CORSプリフライトリクエストを使用してCORSの自動テストを実施
- Origin ヘッダーと Access-Control-Request-Method ヘッダーを持つ OPTIONS リクエスト
- ミドルウェアはリクエストを横取りし、適切なCORSヘッダーと共に情報提供のために 200 または 400 のレスポンスを返す
- 詳細
- テスト方法
- CORSプリフライトリクエストを設定
- Originヘッダーにテストしたいオリジンを設定
- Access-Control-Request-MethodにテストしたいHTTPメソッドを設定
- OPTIONSリクエストを実施
- HTTPステータスコードを確認
- 200ならアクセス可能
- 400ならアクセス不可能
- レスポンスのヘッダーを確認
- ステータスコードが200の場合
- access-control-allow-originに送信したオリジンが設定されている
- ステータスコードが400の場合
- access-control-allow-originが設定されていないこと
- ステータスコードが200の場合
- CORSプリフライトリクエストを設定
test_cors.py
"""CORSのテスト."""
from fastapi import status
from fastapi.testclient import TestClient
from pytest import fixture
# FastAPIのインスタンスをimport
from main import app
@fixture
def client():
"""テスト用のクライアント."""
return TestClient(app)
def test_allowed_cors(client):
"""CORSに設定されているパスがアクセス可能なことをテスト."""
url = "http://allowed.origin.com"
headers = {
"Origin": url,
"Access-Control-Request-Method": "GET"
}
response = client.options("/", headers=headers)
assert status.HTTP_200_OK == response.status_code
assert response.headers["access-control-allow-origin"] == url
def test_disallowed_cors(client):
"""CORSに設定されてないパスがアクセス不可能なことをテスト."""
url = "http://disallowed.origin.com"
headers = {
"Origin": url,
"Access-Control-Request-Method": "GET"
}
response = client.options("/", headers=headers)
assert status.HTTP_400_BAD_REQUEST == response.status_code
assert "access-control-allow-origin" not in response.headers