Update using PyJWT instead of python-jose in Japanese translation

This commit is contained in:
Shishin Mo 2024-06-08 01:28:54 +09:00
parent ceaed0a447
commit f997fa49a4
1 changed files with 38 additions and 43 deletions

View File

@ -1,4 +1,4 @@
# パスワードおよびハッシュ化によるOAuth2、JWTトークンによるBearer
# パスワード(およびハッシュ化)による OAuth2、JWT トークンによる Bearer
これでセキュリティの流れが全てわかったので、<abbr title="JSON Web Tokens">JWT</abbr>トークンと安全なパスワードのハッシュ化を使用して、実際にアプリケーションを安全にしてみましょう。
@ -8,9 +8,9 @@
## JWT について
JWTとは「JSON Web Tokens」の略称です。
JWT とは「JSON Web Tokens」の略称です。
JSONオブジェクトをスペースのない長く密集した文字列で表現したトークンの仕様です。例えば次のようになります
JSON オブジェクトをスペースのない長く密集した文字列で表現したトークンの仕様です。例えば次のようになります:
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
@ -20,34 +20,30 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4
しかし、トークンは署名されているため、あなたが発行したトークンを受け取った人は、あなたが実際に発行したということを検証できます。
例えば、1週間の有効期限を持つトークンを作成したとします。ユーザーが翌日そのトークンを持って戻ってきたとき、そのユーザーはまだシステムにログインしていることがわかります。
例えば、1 週間の有効期限を持つトークンを作成したとします。ユーザーが翌日そのトークンを持って戻ってきたとき、そのユーザーはまだシステムにログインしていることがわかります。
1週間後、トークンが期限切れとなるとどうなるでしょうかユーザーは認可されず、新しいトークンを得るために再びサインインしなければなりません。また、ユーザーまたは第三者がトークンを修正して有効期限を変更しようとした場合、署名が一致しないため、トークンの修正を検知できます。
1 週間後、トークンが期限切れとなるとどうなるでしょうか?ユーザーは認可されず、新しいトークンを得るために再びサインインしなければなりません。また、ユーザー(または第三者)がトークンを修正して有効期限を変更しようとした場合、署名が一致しないため、トークンの修正を検知できます。
JWT トークンを使って遊んでみたいという方は、<a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a> をチェックしてください。
## `python-jose` のインストール
## `PyJWT`のインストール
PythonでJWTトークンの生成と検証を行うために、`python-jose`をインストールする必要があります:
Python JWT トークンの生成と検証を行うために、`PyJWT`をインストールする必要があります:
<div class="termy">
```console
$ pip install python-jose[cryptography]
$ pip install pyjwt
---> 100%
```
</div>
また、<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a>だけではなく、暗号を扱うためのパッケージを追加で必要とします。
!!! info "情報"
RSA や ECDSA のようなデジタル署名アルゴリズムを使用する予定がある場合は、暗号化ライブラリの依存関係である`pyjwt[crypto]`をインストールする必要があります。
ここでは、推奨されているものを使用します:<a href="https://cryptography.io/" class="external-link" target="_blank">pyca/cryptography</a>
!!! tip "豆知識"
このチュートリアルでは以前、<a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>を使用していました。
しかし、Python-joseは、PyJWTのすべての機能に加えて、後に他のツールと統合して構築する際におそらく必要となる可能性のあるいくつかの追加機能を提供しています。そのため、代わりにPython-joseを使用するように更新されました。
詳細については、<a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">PyJWT インストールドキュメント</a>を参照してください。
## パスワードのハッシュ化
@ -65,13 +61,13 @@ $ pip install python-jose[cryptography]
## `passlib` のインストール
PassLib は、パスワードのハッシュを処理するための優れたPythonパッケージです。
PassLib は、パスワードのハッシュを処理するための優れた Python パッケージです。
このパッケージは、多くの安全なハッシュアルゴリズムとユーティリティをサポートします。
推奨されるアルゴリズムは「Bcrypt」です。
そのため、Bcryptを指定してPassLibをインストールします
そのため、Bcrypt を指定して PassLib をインストールします:
<div class="termy">
@ -84,13 +80,12 @@ $ pip install passlib[bcrypt]
</div>
!!! tip "豆知識"
`passlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。
`passlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。
例えば、Djangoアプリケーションからデータベース内の同じデータをFastAPIアプリケーションと共有できるだけではなく、同じデータベースを使用してDjangoアプリケーションを徐々に移行することもできます。
また、ユーザーはDjangoアプリまたは**FastAPI**アプリからも、同時にログインできるようになります。
## パスワードのハッシュ化と検証
必要なツールを `passlib`からインポートします。
@ -98,7 +93,7 @@ $ pip install passlib[bcrypt]
PassLib の「context」を作成します。これは、パスワードのハッシュ化と検証に使用されるものです。
!!! tip "豆知識"
PassLibのcontextには、検証だけが許された非推奨の古いハッシュアルゴリズムを含む、様々なハッシュアルゴリズムを使用した検証機能もあります。
PassLib context には、検証だけが許された非推奨の古いハッシュアルゴリズムを含む、様々なハッシュアルゴリズムを使用した検証機能もあります。
例えば、この機能を使用して、別のシステムDjangoなどによって生成されたパスワードを読み取って検証し、Bcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。
@ -115,13 +110,13 @@ PassLib の「context」を作成します。これは、パスワードのハ
```
!!! note "備考"
新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`
新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`
## JWTトークンの取り扱い
## JWT トークンの取り扱い
インストールした複数のモジュールをインポートします。
JWTトークンの署名に使用されるランダムな秘密鍵を生成します。
JWT トークンの署名に使用されるランダムな秘密鍵を生成します。
安全なランダム秘密鍵を生成するには、次のコマンドを使用します:
@ -137,11 +132,11 @@ $ openssl rand -hex 32
そして、出力された文字列を変数`SECRET_KEY`にコピーします。(例に記載している秘密鍵は実際に使用しないでください)
JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定した変数`ALGORITHM`を作成します。
JWT トークンの署名に使用するアルゴリズム`"HS256"`を指定した変数`ALGORITHM`を作成します。
トークンの有効期限を指定した変数`ACCESS_TOKEN_EXPIRE_MINUTES`を作成します。
レスポンスのトークンエンドポイントで使用するPydanticモデルを定義します。
レスポンスのトークンエンドポイントで使用する Pydantic モデルを定義します。
新しいアクセストークンを生成するユーティリティ関数を作成します。
@ -151,11 +146,11 @@ JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定し
## 依存関係の更新
`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回はJWTトークンを使用します。
`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回は JWT トークンを使用します。
受け取ったトークンを復号して検証し、現在のユーザーを返します。
トークンが無効な場合は、すぐにHTTPエラーを返します。
トークンが無効な場合は、すぐに HTTP エラーを返します。
```Python hl_lines="89-106"
{!../../../docs_src/security/tutorial004.py!}
@ -165,31 +160,31 @@ JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定し
トークンの有効期限を表す`timedelta`を作成します。
JWTアクセストークンを作成し、それを返します。
JWT アクセストークンを作成し、それを返します。
```Python hl_lines="115-130"
{!../../../docs_src/security/tutorial004.py!}
```
### JWTの"subject" `sub` についての技術的な詳細
### JWT の"subject" `sub` についての技術的な詳細
JWTの仕様では、トークンのsubjectを表すキー`sub`があるとされています。
JWT の仕様では、トークンの subject を表すキー`sub`があるとされています。
使用するかどうかは任意ですが、`sub`はユーザーの識別情報を入れるように規定されているので、ここで使用します。
JWTは、ユーザーを識別して、そのユーザーがAPI上で直接操作を実行できるようにする以外にも、他の用途で使用されることがあります。
JWT は、ユーザーを識別して、そのユーザーが API 上で直接操作を実行できるようにする以外にも、他の用途で使用されることがあります。
例えば、「車」や「ブログ記事」を識別することができます。
そして、「ドライブ」(車の場合)や「編集」(ブログの場合)など、そのエンティティに関する権限も追加できます。
また、JWTトークンをユーザーまたはボットに渡すことができます。ユーザーは、JWTトークンを使用するだけで、アカウントを持っていなくても、APIが生成したJWTトークンを使ってそれらの行動車の運転、ブログ投稿の編集を実行できるのです。
また、JWT トークンをユーザーまたはボットに渡すことができます。ユーザーは、JWT トークンを使用するだけで、アカウントを持っていなくても、API が生成した JWT トークンを使ってそれらの行動(車の運転、ブログ投稿の編集)を実行できるのです。
これらのアイデアを使用すると、JWTをより高度なシナリオに使用できます。
これらのアイデアを使用すると、JWT をより高度なシナリオに使用できます。
しかしながら、それらのエンティティのいくつかが同じIDを持つ可能性があります。例えば、`foo`(ユーザー`foo`、車 `foo`、ブログ投稿`foo`)などです。
しかしながら、それらのエンティティのいくつかが同じ ID を持つ可能性があります。例えば、`foo`(ユーザー`foo`、車 `foo`、ブログ投稿`foo`)などです。
IDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe`
ID の衝突を回避するために、ユーザーの JWT トークンを作成するとき、sub キーの値にプレフィックスを付けることができます(例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe`
覚えておくべき重要なことは、`sub`キーはアプリケーション全体で一意の識別子を持ち、文字列である必要があるということです。
@ -209,7 +204,7 @@ Username: `johndoe`
Password: `secret`
!!! check "確認"
コードのどこにも平文のパスワード"`secret`"はなく、ハッシュ化されたものしかないことを確認してください。
コードのどこにも平文のパスワード"`secret`"はなく、ハッシュ化されたものしかないことを確認してください。
<img src="/img/tutorial/security/image08.png">
@ -231,21 +226,21 @@ Password: `secret`
<img src="/img/tutorial/security/image10.png">
!!! note "備考"
ヘッダーの`Authorization`には、`Bearer`で始まる値があります。
ヘッダーの`Authorization`には、`Bearer`で始まる値があります。
## `scopes` を使った高度なユースケース
OAuth2には、「スコープ」という概念があります。
OAuth2 には、「スコープ」という概念があります。
これらを利用して、JWTトークンに特定の権限セットを追加することができます。
これらを利用して、JWT トークンに特定の権限セットを追加することができます。
そして、このトークンをユーザーに直接、または第三者に与えて、制限付きでAPIを操作できます。
そして、このトークンをユーザーに直接、または第三者に与えて、制限付きで API を操作できます。
これらの使用方法や**FastAPI**への統合方法については、**高度なユーザーガイド**で後ほど説明します。
## まとめ
ここまでの説明で、OAuth2やJWTなどの規格を使った安全な**FastAPI**アプリケーションを設定することができます。
ここまでの説明で、OAuth2 JWT などの規格を使った安全な**FastAPI**アプリケーションを設定することができます。
ほとんどのフレームワークにおいて、セキュリティを扱うことは非常に複雑な課題となります。
@ -261,6 +256,6 @@ OAuth2には、「スコープ」という概念があります。
しかし、柔軟性、堅牢性、セキュリティを損なうことなく、可能な限りプロセスを簡素化するためのツールを提供します。
また、OAuth2のような安全で標準的なプロトコルを比較的簡単な方法で使用できるだけではなく、実装することもできます。
また、OAuth2 のような安全で標準的なプロトコルを比較的簡単な方法で使用できるだけではなく、実装することもできます。
OAuth2の「スコープ」を使って、同じ基準でより細かい権限システムを実現する方法については、**高度なユーザーガイド**で詳しく説明しています。スコープ付きのOAuth2は、Facebook、Google、GitHub、Microsoft、Twitterなど、多くの大手認証プロバイダが、サードパーティのアプリケーションと自社のAPIとのやり取りをユーザーに代わって認可するために使用している仕組みです。
OAuth2 の「スコープ」を使って、同じ基準でより細かい権限システムを実現する方法については、**高度なユーザーガイド**で詳しく説明しています。スコープ付きの OAuth2 は、Facebook、Google、GitHub、Microsoft、Twitter など、多くの大手認証プロバイダが、サードパーティのアプリケーションと自社の API とのやり取りをユーザーに代わって認可するために使用している仕組みです。