Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌐 Add Japanese translation for docs/tutorial/security/oauth2-jwt.md #3526

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0cfb3ed
Add Japanese translation for - tutorial/security/oauth2-jwt.md
sattosan Jul 13, 2021
af04726
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
338eb0e
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
88d8dfb
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
1c8950d
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
571ef42
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
6e42def
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
2a271b3
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
1fc924f
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
4830f1b
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
c74d85c
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
faca4f5
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
c8d0d71
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
73d0769
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
6e02c2e
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
749b6d3
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
078c80b
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
67a7f60
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 15, 2021
88b9121
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
94594d1
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
aa957e3
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
bc85940
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
2186d5b
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
37672e1
Update docs/ja/docs/tutorial/security/oauth2-jwt.md
sattosan Jul 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
266 changes: 266 additions & 0 deletions docs/ja/docs/tutorial/security/oauth2-jwt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
# パスワード(およびハッシュ化)によるOAuth2、JWTトークンによるBearer

これでセキュリティの流れが全てわかったので、<abbr title="JSON Web Tokens">JWT</abbr>トークンと安全なパスワードのハッシュ化を使用して、実際にアプリケーションを安全にしてみましょう。

このコードは、アプリケーションで実際に使用したり、パスワードハッシュをデータベースに保存するといった用途に利用できます。

本章では、前章の続きから始めて、コードをアップデートしていきます。

## JWT について

JWTとは"JSON Web Token"の略称です。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

JSONオブジェクトをスペースのない長く密集した文字列で表現したトークンの仕様です。例えば次のようになります:

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

これらは暗号化されていないので、誰でもコンテンツから情報を復元できてしまいます。

しかし、トークンは署名されているため、あなたが発行したトークンを受け取った人は、あなたが実際に発行したということを検証できます。

例えば、1週間の有効期限を持つトークンを作成したとします。ユーザーが翌日そのトークンを持って戻ってきたとき、そのユーザーはまだシステムにログインしていることがわかります。

1週間後、トークンが期限切れとなるとどうなるでしょうか?ユーザーは認証されず、新しいトークンを得るために再びサインインしなければなりません。また、ユーザー(または第三者)がトークンを修正して有効期限を変更しようとした場合、署名が一致しないため、トークンの修正を検知できます。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

JWT トークンを使って遊んでみたいという方は、こちらをチェック <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

## `python-jose` のインストール

PythonでJWTトークンを生成して検証するには、`python-jose`をインストールする必要があります:
sattosan marked this conversation as resolved.
Show resolved Hide resolved

<div class="termy">

```console
$ pip install python-jose[cryptography]

---> 100%
```

</div>

また、<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a>だけではなく、暗号を扱うためのパッケージを追加で必要とします。

ここでは、推奨されているものを使用します:<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を使用するように更新されました。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

## パスワードのハッシュ化

"ハッシュ化"とは、あるコンテンツ(ここではパスワード)を、規則性のないバイト列(単なる文字列)に変換することです。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

特徴として、全く同じ内容(全く同じパスワード)を渡しても、全く同じような規則性のないバイト列が得られます。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

しかし、規則性のないバイト列からパスワードに戻すことはできません。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

### パスワードのハッシュ化を使う理由

データベースが盗まれても、ユーザーの平文のパスワードは盗まれず、ハッシュ値だけが盗まれます。

そして、泥棒はそのパスワードを別のシステムで使おうとしますができません(多くのユーザーはどこでも同じパスワードを使用しているため、危険性があります)。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

## `passlib` のインストール

PassLib は、パスワードのハッシュを処理するための優れたPythonパッケージです。

このパッケージは、多くの安全なハッシュアルゴリズムとユーティリティをサポートします。

推奨されるアルゴリズムは"Bcrypt"です。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

そのため、Bcryptを指定してPassLibをインストールします:

<div class="termy">

```console
$ pip install passlib[bcrypt]

---> 100%
```

</div>

!!! tip "豆知識"
`passlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。

例えば、Djangoアプリケーションからデータベース内の同じデータをFastAPIアプリケーションと共有できるだけではなく、同じデータベースを使用してDjangoアプリケーションを徐々に移行することもできます。

また、ユーザーはDjangoアプリまたは**FastAPI**アプリからも、同時にログインできるようになります。


## パスワードのハッシュ化と検証

必要なツールを `passlib`からインポートします。

PassLib の"context"を作成します。これは、パスワードのハッシュと検証に使用されるものです。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

!!! tip "豆知識"
PassLibのcontext には、非推奨の古いものだけを含む様々なハッシュアルゴリズムを使用した検証機能もあります。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

例えば、この機能を使用して、別のシステム(Djangoなど)によって生成されたパスワードを読み取って検証し、Bcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。

そして、同時にそれらはすべてに互換性があります。

ユーザーから送られてきたパスワードをハッシュ化するユーティリティー関数を作成します。

また、受け取ったパスワードが保存されているハッシュと一致するかどうかを検証するユーティリティも作成します。

さらに、ユーザーを認証して返す関数も作成します。

```Python hl_lines="7 48 55-56 59-60 69-75"
{!../../../docs_src/security/tutorial004.py!}
```

!!! note "備考"
新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`

## JWTトークンの取り扱い

インストールした複数のモジュールをインポートします。

JWTトークンの署名に使用されるランダムな秘密鍵を生成します。

安全なランダム秘密鍵を生成するには、次のコマンドを使用します:

<div class="termy">

```console
$ openssl rand -hex 32

09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7
```

</div>

そして、出力された文字列を変数`SECRET_KEY`にコピーします。(例に記載している秘密鍵は実際に使用しないでください)

JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定した変数`ALGORITHM`を作成します。

トークンの有効期限を指定した変数`ACCESS_TOKEN_EXPIRE_MINUTES `を作成します。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

レスポンスのトークンエンドポイントで使用するPydanticモデルを定義します。

新しいアクセストークンを生成するユーティリティ関数を作成します。

```Python hl_lines="6 12-14 28-30 78-86"
{!../../../docs_src/security/tutorial004.py!}
```

## 依存関係の更新

`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回はJWTトークンを使用します。

受け取ったトークンを復号して検証し、現在のユーザーを返します。

トークンが無効な場合は、すぐにHTTPエラーを返します。

```Python hl_lines="89-106"
{!../../../docs_src/security/tutorial004.py!}
```

## `/token` パス操作の更新
sattosan marked this conversation as resolved.
Show resolved Hide resolved

トークンの有効期限を表す`timedelta`を作成します。

JWTアクセストークンを作成し、それを返します。

```Python hl_lines="115-128"
{!../../../docs_src/security/tutorial004.py!}
```

### JWTの"subject" `sub` についての技術的な詳細

JWTの仕様では、トークンのsubjectを表すキー`sub`があるとされています。

使用するかどうかは任意ですが、`sub`にユーザーの識別情報を入れることになるので、ここでは使用しています。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

JWTは、ユーザーを識別して、そのユーザーがAPI上で直接操作を実行できるようにする以外にも、他の用途で使用されることがあります。

例えば、「車」や「ブログ記事」を識別することができます。

そして、「ドライブ」(車の場合)や「編集」(ブログの場合)など、そのエンティティに関する権限も追加できます。

また、JWTトークンをユーザー(またはボット)に渡すことができます。ユーザーは、JWTトークンを使用するだけで、アカウントを持っていなくても、APIが生成したJWTトークンを使ってそれらの行動(車の運転、ブログ投稿の編集)を実行することができるのです。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

これらのアイデアを使用すると、JWTをより高度なシナリオに使用できます。

しかしながら、それらのエンティティのいくつかが同じIDを持つ可能性があります。例えば、 `foo`(ユーザー`foo`、車 `foo`、ブログ投稿` foo`)などです。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

IDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます(例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe`

覚えておくべき重要なことは、`sub`キーはアプリケーション全体で一意の識別子を持ち、文字列である必要があるということです。

## 確認

サーバーを実行し、ドキュメントに移動します:<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>

次のようなユーザーインターフェイスが表示されます:

<img src="/img/tutorial/security/image07.png">

前回と同じ方法でアプリケーションの認証を行います。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

認証情報の使用:
sattosan marked this conversation as resolved.
Show resolved Hide resolved

Username: `johndoe`
Password: `secret`

!!! check "確認"
コードのどこにも平文のパスワード"`secret`"はなく、ハッシュ化されたものしかないことを確認してください。

<img src="/img/tutorial/security/image08.png">

エンドポイント`/users/me/`を呼び出すと、次のようなレスポンスが得られます:

```JSON
{
"username": "johndoe",
"email": "johndoe@example.com",
"full_name": "John Doe",
"disabled": false
}
```

<img src="/img/tutorial/security/image09.png">

開発者ツールを開くと、送信されるデータにはトークンだけが含まれており、パスワードはユーザーを認証してアクセストークンを取得する最初のリクエストでのみ送信され、その後は送信されないことがわかります。

<img src="/img/tutorial/security/image10.png">

!!! note "備考"
ヘッダーの`Authorization`には、`Bearer`で始まる値があります。

## `scopes` を使った高度なユースケース

OAuth2には、"スコープ"という概念があります。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

これらを利用して、JWTトークンに特定の権限セットを追加することができます。

そして、このトークンをユーザーに直接、または第三者に与えて、制限付きでAPIを操作することができます。
sattosan marked this conversation as resolved.
Show resolved Hide resolved

これらの使用方法や**FastAPI**への統合方法については、**高度なユーザーガイド**で後ほど説明します。

## まとめ

ここまでの説明で、OAuth2やJWTなどの規格を使った安全な**FastAPI**アプリケーションを設定することができます。

ほとんどのフレームワークにおいて、セキュリティを扱うことは非常に複雑な課題となります。

簡略化しすぎたパッケージの多くは、データモデルやデータベース、利用可能な機能について多くの妥協をしなければなりません。そして、あまりにも単純化されたパッケージの中には、実はセキュリティ上の欠陥があるものもあります。

---

**FastAPI**は、どのようなデータベース、データモデル、ツールに対しても妥協することはありません。

そのため、プロジェクトに合わせて自由に選択することができます。

また、**FastAPI**は外部パッケージを統合するために複雑な仕組みを必要としないため、`passlib`や`python-jose`のようなよく整備され広く使われている多くのパッケージを直接使用することができます。

しかし、柔軟性、堅牢性、セキュリティを損なうことなく、可能な限りプロセスを簡素化するためのツールを提供します。

また、OAuth2のような安全で標準的なプロトコルを比較的簡単な方法で使用できるだけではなく、実装することもできます。

OAuth2の"スコープ"を使って、同じ基準でより細かい許可システムを実現する方法については、**高度なユーザーガイド**で詳しく説明しています。スコープ付きのOAuth2は、Facebook、Google、GitHub、Microsoft、Twitterなど、多くの大手認証プロバイダが、ユーザーに代わってサードパーティのアプリケーションが自社のAPIとやり取りを許可するために使用されている仕組みです。
sattosan marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions docs/ja/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ nav:
- tutorial/body-updates.md
- セキュリティ:
- tutorial/security/first-steps.md
- tutorial/security/oauth2-jwt.md
- tutorial/middleware.md
- tutorial/cors.md
- tutorial/static-files.md
Expand Down