セキュリティ - 最初の手順¶
あるドメインにバックエンド API があるとします。
そして、別のドメイン、または同じドメインの別のパス(またはモバイル アプリケーション)にフロントエンドがあります。
そして、フロントエンドがユーザー名とパスワードを使用してバックエンドで認証する方法を用意したいと考えています。
FastAPI を使用して OAuth2 でこれを実現できます。
しかし、必要な情報の小さな断片を見つけるためだけに、長い仕様全体を読む時間を節約しましょう。
FastAPI が提供するツールを使用してセキュリティを処理しましょう。
外観¶
まずコードを使用して動作を確認し、その後で何が起こっているのかを理解しましょう。
main.py
を作成する¶
例を main.py
ファイルにコピーします
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from typing_extensions import Annotated
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
ヒント
可能な場合は、Annotated
バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
実行する¶
情報
python-multipart
パッケージは、pip install "fastapi[standard]"
コマンドを実行すると、FastAPI とともに自動的にインストールされます。
ただし、pip install fastapi
コマンドを使用する場合、python-multipart
パッケージはデフォルトでは含まれません。
手動でインストールするには、仮想環境を作成し、アクティブ化してから、次のコマンドでインストールしてください
$ pip install python-multipart
これは、OAuth2 が username
と password
を送信するために「フォームデータ」を使用するためです。
次のコマンドで例を実行します
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
確認する¶
インタラクティブ ドキュメントにアクセスします: http://127.0.0.1:8000/docs。
次のようなものが表示されます
「認証ボタン!」
真新しい「認証」ボタンが表示されます。
また、パス操作の右上に小さな鍵が表示され、クリックできます。
クリックすると、username
と password
(およびその他のオプション フィールド)を入力するための小さな認証フォームが表示されます
注記
フォームに入力する内容は重要ではありません。まだ機能しません。しかし、いずれは機能するようになります。
これはもちろん、最終ユーザー向けのフロントエンドではありませんが、すべての API をインタラクティブにドキュメント化するための優れた自動ツールです。
フロントエンドチーム(あなた自身の場合もあります)が使用できます。
サードパーティのアプリケーションやシステムで使用できます。
また、同じアプリケーションをデバッグ、チェック、テストするために、あなた自身で使用することもできます。
password
フロー¶
少し戻って、全体像を理解しましょう。
password
「フロー」は、OAuth2 で定義されているセキュリティと認証を処理する方法(「フロー」)の1つです。
OAuth2 は、バックエンドまたは API がユーザーを認証するサーバーから独立できるように設計されました。
しかし、この場合は、同じ FastAPI アプリケーションが API と認証を処理します。
それでは、その簡略化された観点から見ていきましょう。
- ユーザーはフロントエンドで
username
とpassword
を入力し、Enter
キーを押します。 - フロントエンド(ユーザーのブラウザで実行されている)は、その
username
とpassword
を API の特定の URL(tokenUrl="token"
で宣言されている)に送信します。 - API は
username
とpassword
をチェックし、「トークン」で応答します(まだこれを実装していません)。- 「トークン」は、後でこのユーザーを確認するために使用できる、あるコンテンツを含む単なる文字列です。
- 通常、トークンは一定時間後に期限切れになるように設定されています。
- そのため、ユーザーは後で再度ログインする必要があります。
- また、トークンが盗まれた場合、リスクは少なくなります。永久に機能する永続キーのようなものではありません(ほとんどの場合)。
- フロントエンドはそのトークンを一時的にどこかに保存します。
- ユーザーはフロントエンドをクリックして、フロントエンド Web アプリの別のセクションに移動します。
- フロントエンドは API からさらにデータを取得する必要があります。
- しかし、その特定のエンドポイントには認証が必要です。
- そのため、API で認証するには、
Bearer
とトークンを値とするAuthorization
ヘッダーを送信します。 - トークンに
foobar
が含まれている場合、Authorization
ヘッダーの内容はBearer foobar
になります。
FastAPI の OAuth2PasswordBearer
¶
FastAPI は、これらのセキュリティ機能を実装するための、さまざまなレベルの抽象化を持つツールを提供します。
この例では、OAuth2 を Password フローで使用し、Bearer トークンを使用します。 OAuth2PasswordBearer
クラスを使用してこれを行います。
情報
「bearer」トークンは唯一の選択肢ではありません。
しかし、私たちのユースケースには最適です。
また、OAuth2 の専門家で、ニーズに合った別のオプションがある理由を正確に知っている場合を除き、ほとんどのユースケースに最適です。
その場合は、FastAPI はそれを構築するためのツールも提供します。
OAuth2PasswordBearer
クラスのインスタンスを作成するとき、tokenUrl
パラメーターを渡します。このパラメーターには、クライアント(ユーザーのブラウザで実行されているフロントエンド)がトークンを取得するために username
と password
を送信するために使用する URL が含まれています。
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from typing_extensions import Annotated
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
ヒント
可能な場合は、Annotated
バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
ヒント
ここで、tokenUrl="token"
は、まだ作成していない相対 URL token
を参照しています。相対 URL であるため、./token
と同等です。
相対 URL を使用しているため、API が https://example.com/
にある場合、https://example.com/token
を参照します。ただし、API が https://example.com/api/v1/
にある場合、https://example.com/api/v1/token
を参照します。
プロキシの背後のような高度なユースケースでもアプリケーションが動作し続けるようにするには、相対 URL を使用することが重要です。
このパラメーターは、そのエンドポイント/ *パス操作*を作成するのではなく、URL /token
がクライアントがトークンを取得に使用すべき URL であることを宣言します。その情報は OpenAPI で、次にインタラクティブな API ドキュメントシステムで使用されます。
すぐに実際のパス操作も作成します。
情報
非常に厳格な「Pythonista」であれば、token_url
ではなく tokenUrl
というパラメーター名のスタイルが嫌いな場合があります。
これは、OpenAPI 仕様と同じ名前を使用しているためです。そのため、これらのセキュリティスキームの詳細を調べる必要がある場合は、コピーして貼り付けるだけで、それに関する詳細情報を見つけることができます。
oauth2_scheme
変数は OAuth2PasswordBearer
のインスタンスですが、「呼び出し可能」でもあります。
次のように呼び出すことができます。
oauth2_scheme(some, parameters)
そのため、Depends
で使用できます。
それを使用する¶
これで、Depends
を使用して、依存関係にその oauth2_scheme
を渡すことができます。
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from typing_extensions import Annotated
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
ヒント
可能な場合は、Annotated
バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
この依存関係は、*パス操作関数*のパラメーター token
に割り当てられる str
を提供します。
FastAPI は、この依存関係を使用して OpenAPI スキーマ(および自動 API ドキュメント)で「セキュリティスキーム」を定義できることを認識します。
「技術的な詳細」
FastAPI は、依存関係で宣言された OAuth2PasswordBearer
クラスを使用して OpenAPI でセキュリティスキームを定義できることを認識します。これは、fastapi.security.oauth2.OAuth2
を継承し、さらに fastapi.security.base.SecurityBase
を継承しているためです。
OpenAPI(および自動 API ドキュメント)と統合するすべてのセキュリティユーティリティは SecurityBase
を継承します。これが、FastAPI が OpenAPI にそれらを統合する方法を知ることができる方法です。
それがすること¶
リクエストでその Authorization
ヘッダーを探し、値が Bearer
とトークンであるかどうかを確認し、トークンを str
として返します。
Authorization
ヘッダーが表示されない場合、または値に Bearer
トークンがない場合、401 ステータスコードエラー(UNAUTHORIZED
)を直接返します。
エラーを返すためにトークンが存在するかどうかを確認する必要さえありません。関数が実行されると、そのトークンに str
があることが確実です。
インタラクティブドキュメントですでに試すことができます
まだトークンの有効性を検証していませんが、それはすでに始まりです。
要約¶
そのため、わずか 3 行か 4 行の追加で、すでに原始的な形式のセキュリティが実現しています。