コンテンツにスキップ

セキュリティ - 最初の手順

あるドメインにバックエンド 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

これは、OAuth2usernamepassword を送信するために「フォームデータ」を使用するためです。

次のコマンドで例を実行します

$ 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

次のようなものが表示されます

「認証ボタン!」

真新しい「認証」ボタンが表示されます。

また、パス操作の右上に小さな鍵が表示され、クリックできます。

クリックすると、usernamepassword(およびその他のオプション フィールド)を入力するための小さな認証フォームが表示されます

注記

フォームに入力する内容は重要ではありません。まだ機能しません。しかし、いずれは機能するようになります。

これはもちろん、最終ユーザー向けのフロントエンドではありませんが、すべての API をインタラクティブにドキュメント化するための優れた自動ツールです。

フロントエンドチーム(あなた自身の場合もあります)が使用できます。

サードパーティのアプリケーションやシステムで使用できます。

また、同じアプリケーションをデバッグ、チェック、テストするために、あなた自身で使用することもできます。

password フロー

少し戻って、全体像を理解しましょう。

password 「フロー」は、OAuth2 で定義されているセキュリティと認証を処理する方法(「フロー」)の1つです。

OAuth2 は、バックエンドまたは API がユーザーを認証するサーバーから独立できるように設計されました。

しかし、この場合は、同じ FastAPI アプリケーションが API と認証を処理します。

それでは、その簡略化された観点から見ていきましょう。

  • ユーザーはフロントエンドで usernamepassword を入力し、Enter キーを押します。
  • フロントエンド(ユーザーのブラウザで実行されている)は、その usernamepassword を API の特定の URL(tokenUrl="token" で宣言されている)に送信します。
  • API は usernamepassword をチェックし、「トークン」で応答します(まだこれを実装していません)。
    • 「トークン」は、後でこのユーザーを確認するために使用できる、あるコンテンツを含む単なる文字列です。
    • 通常、トークンは一定時間後に期限切れになるように設定されています。
      • そのため、ユーザーは後で再度ログインする必要があります。
      • また、トークンが盗まれた場合、リスクは少なくなります。永久に機能する永続キーのようなものではありません(ほとんどの場合)。
  • フロントエンドはそのトークンを一時的にどこかに保存します。
  • ユーザーはフロントエンドをクリックして、フロントエンド Web アプリの別のセクションに移動します。
  • フロントエンドは API からさらにデータを取得する必要があります。
    • しかし、その特定のエンドポイントには認証が必要です。
    • そのため、API で認証するには、Bearer とトークンを値とする Authorization ヘッダーを送信します。
    • トークンに foobar が含まれている場合、Authorization ヘッダーの内容は Bearer foobar になります。

FastAPIOAuth2PasswordBearer

FastAPI は、これらのセキュリティ機能を実装するための、さまざまなレベルの抽象化を持つツールを提供します。

この例では、OAuth2Password フローで使用し、Bearer トークンを使用します。 OAuth2PasswordBearer クラスを使用してこれを行います。

情報

「bearer」トークンは唯一の選択肢ではありません。

しかし、私たちのユースケースには最適です。

また、OAuth2 の専門家で、ニーズに合った別のオプションがある理由を正確に知っている場合を除き、ほとんどのユースケースに最適です。

その場合は、FastAPI はそれを構築するためのツールも提供します。

OAuth2PasswordBearer クラスのインスタンスを作成するとき、tokenUrl パラメーターを渡します。このパラメーターには、クライアント(ユーザーのブラウザで実行されているフロントエンド)がトークンを取得するために usernamepassword を送信するために使用する 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 行の追加で、すでに原始的な形式のセキュリティが実現しています。