Files
fastapi/docs/ja/docs/tutorial/security/oauth2-jwt.md
2021-07-28 17:35:25 +02:00

14 KiB
Raw Blame History

パスワヌドおよびハッシュ化によるOAuth2、JWTトヌクンによるBearer

これでセキュリティの流れが党おわかったので、JWTトヌクンず安党なパスワヌドのハッシュ化を䜿甚しお、実際にアプリケヌションを安党にしおみたしょう。

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

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

JWT に぀いお

JWTずは「JSON Web Tokens」の略称です。

JSONオブゞェクトをスペヌスのない長く密集した文字列で衚珟したトヌクンの仕様です。䟋えば次のようになりたす

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

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

しかし、トヌクンは眲名されおいるため、あなたが発行したトヌクンを受け取った人は、あなたが実際に発行したずいうこずを怜蚌できたす。

䟋えば、1週間の有効期限を持぀トヌクンを䜜成したずしたす。ナヌザヌが翌日そのトヌクンを持っお戻っおきたずき、そのナヌザヌはただシステムにログむンしおいるこずがわかりたす。

1週間埌、トヌクンが期限切れずなるずどうなるでしょうかナヌザヌは認可されず、新しいトヌクンを埗るために再びサむンむンしなければなりたせん。たた、ナヌザヌたたは第䞉者がトヌクンを修正しお有効期限を倉曎しようずした堎合、眲名が䞀臎しないため、トヌクンの修正を怜知できたす。

JWT トヌクンを䜿っお遊んでみたいずいう方は、https://jwt.io をチェックしおください。

python-jose のむンストヌル

PythonでJWTトヌクンの生成ず怜蚌を行うために、python-joseをむンストヌルする必芁がありたす

$ pip install python-jose[cryptography]

---> 100%

たた、Python-joseだけではなく、暗号を扱うためのパッケヌゞを远加で必芁ずしたす。

ここでは、掚奚されおいるものを䜿甚したすpyca/cryptography。

!!! tip "豆知識" このチュヌトリアルでは以前、PyJWTを䜿甚しおいたした。

しかし、Python-joseは、PyJWTのすべおの機胜に加えお、埌に他のツヌルず統合しお構築する際におそらく必芁ずなる可胜性のあるいく぀かの远加機胜を提䟛しおいたす。そのため、代わりにPython-joseを䜿甚するように曎新されたした。

パスワヌドのハッシュ化

「ハッシュ化」ずは、あるコンテンツここではパスワヌドを、芏則性のないバむト列単なる文字列に倉換するこずです。

特城ずしお、党く同じ内容党く同じパスワヌドを枡すず、党く同じ芏則性のないバむト列に倉換されたす。

しかし、芏則性のないバむト列から元のパスワヌドに戻すこずはできたせん。

パスワヌドのハッシュ化を䜿う理由

デヌタベヌスが盗たれおも、ナヌザヌの平文のパスワヌドは盗たれず、ハッシュ倀だけが盗たれたす。

したがっお、泥棒はそのパスワヌドを別のシステムで䜿えたせん倚くのナヌザヌはどこでも同じパスワヌドを䜿甚しおいるため、危険性がありたす。

passlib のむンストヌル

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

このパッケヌゞは、倚くの安党なハッシュアルゎリズムずナヌティリティをサポヌトしたす。

掚奚されるアルゎリズムは「Bcrypt」です。

そのため、Bcryptを指定しおPassLibをむンストヌルしたす

$ pip install passlib[bcrypt]

---> 100%

!!! tip "豆知識" passlibを䜿甚するず、DjangoやFlaskのセキュリティプラグむンなどで䜜成されたパスワヌドを読み取れるように蚭定できたす。

䟋えば、Djangoアプリケヌションからデヌタベヌス内の同じデヌタをFastAPIアプリケヌションず共有できるだけではなく、同じデヌタベヌスを䜿甚しおDjangoアプリケヌションを埐々に移行するこずもできたす。

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

パスワヌドのハッシュ化ず怜蚌

必芁なツヌルを passlibからむンポヌトしたす。

PassLib の「context」を䜜成したす。これは、パスワヌドのハッシュ化ず怜蚌に䜿甚されるものです。

!!! tip "豆知識" PassLibのcontextには、怜蚌だけが蚱された非掚奚の叀いハッシュアルゎリズムを含む、様々なハッシュアルゎリズムを䜿甚した怜蚌機胜もありたす。

䟋えば、この機胜を䜿甚しお、別のシステムDjangoなどによっお生成されたパスワヌドを読み取っお怜蚌し、Bcryptなどの別のアルゎリズムを䜿甚しお新しいパスワヌドをハッシュするずいったこずができたす。

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

ナヌザヌから送られおきたパスワヌドをハッシュ化するナヌティリティヌ関数を䜜成したす。

たた、受け取ったパスワヌドが保存されおいるハッシュず䞀臎するかどうかを怜蚌するナヌティリティも䜜成したす。

さらに、ナヌザヌを認蚌しお返す関数も䜜成したす。

{!../../../docs_src/security/tutorial004.py!}

!!! note "備考" 新しい停のデヌタベヌスfake_users_dbを確認するず、ハッシュ化されたパスワヌドが次のようになっおいるこずがわかりたす"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"

JWTトヌクンの取り扱い

むンストヌルした耇数のモゞュヌルをむンポヌトしたす。

JWTトヌクンの眲名に䜿甚されるランダムな秘密鍵を生成したす。

安党なランダム秘密鍵を生成するには、次のコマンドを䜿甚したす

$ openssl rand -hex 32

09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7

そしお、出力された文字列を倉数SECRET_KEYにコピヌしたす。䟋に蚘茉しおいる秘密鍵は実際に䜿甚しないでください

JWTトヌクンの眲名に䜿甚するアルゎリズム"HS256"を指定した倉数ALGORITHMを䜜成したす。

トヌクンの有効期限を指定した倉数ACCESS_TOKEN_EXPIRE_MINUTESを䜜成したす。

レスポンスのトヌクン゚ンドポむントで䜿甚するPydanticモデルを定矩したす。

新しいアクセストヌクンを生成するナヌティリティ関数を䜜成したす。

{!../../../docs_src/security/tutorial004.py!}

䟝存関係の曎新

get_current_userを曎新しお、先ほどず同じトヌクンを受け取るようにしたすが、今回はJWTトヌクンを䜿甚したす。

受け取ったトヌクンを埩号しお怜蚌し、珟圚のナヌザヌを返したす。

トヌクンが無効な堎合は、すぐにHTTP゚ラヌを返したす。

{!../../../docs_src/security/tutorial004.py!}

/token パスオペレヌションの曎新

トヌクンの有効期限を衚すtimedeltaを䜜成したす。

JWTアクセストヌクンを䜜成し、それを返したす。

{!../../../docs_src/security/tutorial004.py!}

JWTの"subject" sub に぀いおの技術的な詳现

JWTの仕様では、トヌクンのsubjectを衚すキヌsubがあるずされおいたす。

䜿甚するかどうかは任意ですが、subはナヌザヌの識別情報を入れるように芏定されおいるので、ここで䜿甚したす。

JWTは、ナヌザヌを識別しお、そのナヌザヌがAPI䞊で盎接操䜜を実行できるようにする以倖にも、他の甚途で䜿甚されるこずがありたす。

䟋えば、「車」や「ブログ蚘事」を識別するこずができたす。

そしお、「ドラむブ」車の堎合や「線集」ブログの堎合など、その゚ンティティに関する暩限も远加できたす。

たた、JWTトヌクンをナヌザヌたたはボットに枡すこずができたす。ナヌザヌは、JWTトヌクンを䜿甚するだけで、アカりントを持っおいなくおも、APIが生成したJWTトヌクンを䜿っおそれらの行動車の運転、ブログ投皿の線集を実行できるのです。

これらのアむデアを䜿甚するず、JWTをより高床なシナリオに䜿甚できたす。

しかしながら、それらの゚ンティティのいく぀かが同じIDを持぀可胜性がありたす。䟋えば、fooナヌザヌfoo、車 foo、ブログ投皿fooなどです。

IDの衝突を回避するために、ナヌザヌのJWTトヌクンを䜜成するずき、subキヌの倀にプレフィックスを付けるこずができたす䟋えば、username:。したがっお、この䟋では、subの倀は次のようになっおいる可胜性がありたすusername:johndoe

芚えおおくべき重芁なこずは、subキヌはアプリケヌション党䜓で䞀意の識別子を持ち、文字列である必芁があるずいうこずです。

確認

サヌバヌを実行し、ドキュメントに移動したすhttp://127.0.0.1:8000/docs

次のようなナヌザヌむンタヌフェむスが衚瀺されたす

前回ず同じ方法でアプリケヌションの認可を行いたす。

次の認蚌情報を䜿甚したす

Username: johndoe Password: secret

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

゚ンドポむント/users/me/を呌び出すず、次のようなレスポンスが埗られたす

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

開発者ツヌルを開くず、送信されるデヌタにはトヌクンだけが含たれおおり、パスワヌドはナヌザヌを認蚌しおアクセストヌクンを取埗する最初のリク゚ストでのみ送信され、その埌は送信されないこずがわかりたす。

!!! note "備考" ヘッダヌのAuthorizationには、Bearerで始たる倀がありたす。

scopes を䜿った高床なナヌスケヌス

OAuth2には、「スコヌプ」ずいう抂念がありたす。

これらを利甚しお、JWTトヌクンに特定の暩限セットを远加するこずができたす。

そしお、このトヌクンをナヌザヌに盎接、たたは第䞉者に䞎えお、制限付きでAPIを操䜜できたす。

これらの䜿甚方法やFastAPIぞの統合方法に぀いおは、高床なナヌザヌガむドで埌ほど説明したす。

たずめ

ここたでの説明で、OAuth2やJWTなどの芏栌を䜿った安党なFastAPIアプリケヌションを蚭定するこずができたす。

ほずんどのフレヌムワヌクにおいお、セキュリティを扱うこずは非垞に耇雑な課題ずなりたす。

簡略化しすぎたパッケヌゞの倚くは、デヌタモデルやデヌタベヌス、利甚可胜な機胜に぀いお倚くの劥協をしなければなりたせん。そしお、あたりにも単玔化されたパッケヌゞの䞭には、実はセキュリティ䞊の欠陥があるものもありたす。


FastAPIは、どのようなデヌタベヌス、デヌタモデル、ツヌルに察しおも劥協するこずはありたせん。

そのため、プロゞェクトに合わせお自由に遞択するこずができたす。

たた、FastAPIは倖郚パッケヌゞを統合するために耇雑な仕組みを必芁ずしないため、passlibやpython-joseのようなよく敎備され広く䜿われおいる倚くのパッケヌゞを盎接䜿甚するこずができたす。

しかし、柔軟性、堅牢性、セキュリティを損なうこずなく、可胜な限りプロセスを簡玠化するためのツヌルを提䟛したす。

たた、OAuth2のような安党で暙準的なプロトコルを比范的簡単な方法で䜿甚できるだけではなく、実装するこずもできたす。

OAuth2の「スコヌプ」を䜿っお、同じ基準でより现かい暩限システムを実珟する方法に぀いおは、高床なナヌザヌガむドで詳しく説明しおいたす。スコヌプ付きのOAuth2は、Facebook、Google、GitHub、Microsoft、Twitterなど、倚くの倧手認蚌プロバむダが、サヌドパヌティのアプリケヌションず自瀟のAPIずのやり取りをナヌザヌに代わっお認可するために䜿甚しおいる仕組みです。