はじめに
こんにちは、山本です。APIを実装するとき、個人的には認証が一番難しいと思っています。しかし、FastAPIでは簡単に認証が実装ができるような仕組みがあります。本記事では、私が公式ドキュメントを読んで学んだ認証の方法を実装を動かしながら紹介します。
認証とは
認証はAPIを特定のユーザしか利用できないようにする技術です。APIはエンドポイント(URL)を知っていれば基本的に誰でもアクセスでき、個人情報などの流出につながる恐れがあります。そこで、アクセスするユーザが誰なのかを認証(authentication)し、そのユーザがどの情報(resource)にアクセスできるかを認可(authorization)します。
はてなブログでのGoogleによるソーシャルログインを例として説明します。Googleのメアドとパスワードの入力が認証にあたり、はてなブログがGoogleのアカウントのプロフィール写真や名前を利用することを許可することが認可にあたります。
認証の実装を他のフレームワークと比較
続いて、FastAPIの認証の実装を他のフレームワークと比較して利点を二つ説明します。
1 認証の動作確認が楽
認証の動作確認は、Postman等のAPIクライアントを準備する必要があります。しかし。FastAPIはドキュメントから動作確認が行えるため、それらの準備が不要です。
2 実装者がOAuthの仕様を十分に理解する必要がない
FastAPIの認証の仕様はOAuth2に基づいています。そのため、FastAPIの使い方に沿って実装をするだけで、OAuth2等の標準的な仕様に沿ったAPIができます。
以上の点から、FastAPIを利用することで、学習コストが少なく簡単に認証を実装できると思います。
実装について
実装内容はFastAPIを使い認証しデータはSQLiteで保存します。今回の実装は認可は行っておりません。参考にしたのは、
- SQL(Relational)Databases
- OAuth2 with Password (and hashing), Bearer with JWT tokens
- full-stack-fastapi-postgresql
でどれも公式のものです。公式ドキュメントにはPython3.10で説明されていたため、3.10で実装を行いました。私の実装したコードはこちらです。
実行
まず、Python3.10以上の実行環境を用意してください。 次にソースコードをダウンロードし、カレントディレクトリを変更します。
git clone https://github.com/ydaigo/fastapi-auth.git cd fastapi-auth
依存関係をインストールします。
pip install -r requirements.txt
FastAPIを実行します。
uvicorn main:app --reload --port 5000
127.0.0.1:5000/docsでドキュメントにアクセスできます。 ああああ
動かしてみる
FastAPIの特徴はこのドキュメントなのでこれを使ってAPIを呼んでみましょう。
まず、ユーザ登録を行います。POST /users
を押すとリクエストやレスポンスの仕様が表示されます。
「Try it out」を押すとリクエストボディを編集でき「Excute」からAPIにリクエストを投げることができます。email、username、passwordの項目を自由に変更してみてください。
ステータスコードの200が返ってきて、ユーザを登録できました。すでに同じusernameやemailが登録されている場合はステータスコードの400が返却されます。
このアカウントを使って、トークンを発行します。画面右上の「Autherize」を押すと認証画面が出てきます。
先ほど登録したusernameとpasswordを入力し、「Authorize」を押します。
認証ができました。「Close」を押して閉じます。
認証が完了したため鍵マークの鍵がかかっていることが確認できます。
GET /user/me
は認証したユーザの情報を返却します。先ほどと同じように「Try it out」から「Excute」を押します。
先ほど登録したユーザデータが返却されました。パスワードはそのままの保存ではなくハッシュ化しています。また、認証したユーザ以外がアクセスしようとするとステータスコードの401が返却されユーザデータを取得できません。
ドキュメントからユーザー登録、認証まで簡単に動かせましたね。次に中身の解説に入ります。
データベース連携
データベースはSQLiteを利用しており、/common/session.py
でORMライブラリのSQLAlchemyを利用してデータベースの設定を行っています。SQLiteはDBサーバを作成する必要がないため、このようなデモアプリを動かすときには便利です。データベースの定義は/common/models.py
に記載されており、起動時にこの定義に基づいてデータベースが作られます。
ユーザ登録
ユーザ登録の流れを説明します。/api/db_api.py
のcreate_user関数で定義したエンドポイントにポストリクエストで登録したい情報を送信します。その情報を/common/crud.py
のcreate_userメソッドでデータベースにユーザの登録を行います。この時、パスワードはライブラリのPasslibでBCryptというハッシュ化アルゴリズムでハッシュ値として保存します。これによって、データベースの情報が流出してもパスワードが流出することを防ぐことができます。
トークン発行と検証
続いてトークン発行と検証について説明します。トークンの発行は/api/auth_api.py
のlogin_for_access_token関数で定義したエンドポイントにusernameとパスワードを送信することでトークンを発行します。トークンはJWTというJSON形式のデータをBase64でエンコードしそれを共通鍵のHS256で署名したものです。このトークンがusernameとパスワードの代わりになります。トークンが正しいことの検証は/api/auth_api.py
のget_current_user関数でトークンのデコードを行い、usernameを取得します。このusernameを利用することで誰がアクセスしたのかをFastAPIは理解します。トークンの発行と検証はjoseというライブラリを利用しています。
おわりに
いかがでしたか?この記事を通して、FastAPIでの認証の実装を理解できたと思います。仕組みについての解説は少なめですが、ソースコードを公開しているため、コードを読みつつ自分で調べてみてください。FastAPIは日本語でのドキュメントもあり大変わかりやすいのでドキュメントを読んだ後に、このソースコードを読むというのも良さそうです。