Leapcell: The Best of Serverless Web Hosting
FastAPIでのJWTを用いた認証の実装
はじめに
現代のウェブアプリケーション開発において、認証はシステムのセキュリティを確保する上で重要な要素です。JSON Web Token (JWT) は、JSONに基づくオープン標準 (RFC 7519) として、コンパクトでセキュアな特性から、分散型サイトのシングルサインオン (SSO) シナリオで広く利用されています。FastAPIはPythonベースの高性能なウェブフレームワークです。この記事では、与えられたJWT実装コードを用いて、FastAPIでJWTを使った認証を行う方法を紹介します。
JWTの基本
JWTとは?
JSON Web Token (JWT) は、ネットワークアプリケーション環境間でクレームを伝達するために設計されています。コンパクトでセキュアであり、分散型サイトのシングルサインオンシナリオに特に適しています。JWTのクレームは、認証されたユーザーのID情報をアイデンティティプロバイダとサービスプロバイダ間で伝達し、リソースサーバからリソースを取得するためによく使われ、またビジネスロジックで必要な他のクレーム情報を追加することもできます。このトークンは、直接認証に使用したり、暗号化したりすることができます。
JWTの構成
JWTは3つのセグメント情報から構成されています。
- ヘッダー:通常、ファイルタイプと暗号化アルゴリズムを宣言します。
- ペイロード:JSON形式で送信するデータを記録します。
- 署名:検証に使用する署名です。
base64UrlEncodeメソッド
JWTを生成する際には、署名に base64UrlEncode
メソッドが使用されます。このメソッドの基本的な機能は以下の通りです。
- UTF-8でエンコードされた文字列
s1
を入力します。 - 文字列
s1
をbase64でエンコードして文字列s2
を取得します。 -
s2
の末尾に等号がある場合、末尾のすべての等号を削除します。 -
s2
の中にプラス記号 (+
) がある場合、すべてのプラス記号をマイナス記号 (-
) に置き換えます。 -
s2
の中にスラッシュ (/
) がある場合、すべてのスラッシュをアンダースコア (_
) に置き換えます。
以下は、このメソッドを実装するPythonコードです。
import hmac
import base64
from hashlib import sha256
from urllib import parse as urlp
def b64url(str1):
if type(str1) == str:
return str(base64.b64encode(str1.encode('utf-8')), encoding="utf-8").strip('=').replace('+', '-').replace('/', '_')
elif type(str1) == bytes:
return str(base64.b64encode(str1), encoding="utf-8").strip('=').replace('+', '-').replace('/', '_')
else:
raise TypeError("The type of given argument must be string or bytes")
HS256で暗号化されたJWTの生成
以下は、上記の b64url
関数を使用してHS256で暗号化されたJWTを生成するコードです。
# Enter Your Infomation Here ...
header = b64url('{"alg":"HS256","typ":"JWT"}')
payload = b64url('{"sub":"1234567890","name":"John Doe","iat":1516239022}')
secret = 'happynewyear'.encode('utf-8')
# ###
sig = b64url(hmac.new(
secret, (header + '.' + payload).encode('utf-8'), digestmod=sha256
).digest())
jwt = header + '.' + payload + '.' + sig
print(jwt)
FastAPIでのJWTの統合
依存関係のインストール
始める前に、fastapi
と uvicorn
をインストールする必要があります。以下のコマンドを使用してインストールできます。
pip install fastapi uvicorn
実装手順
1. FastAPIアプリケーションの作成
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import hmac
import base64
from hashlib import sha256
app = FastAPI()
# Define the b64url function
def b64url(str1):
if type(str1) == str:
return str(base64.b64encode(str1.encode('utf-8')), encoding="utf-8").strip('=').replace('+', '-').replace('/', '_')
elif type(str1) == bytes:
return str(base64.b64encode(str1), encoding="utf-8").strip('=').replace('+', '-').replace('/', '_')
else:
raise TypeError("The type of given argument must be string or bytes")
# Secret key
SECRET_KEY = 'happynewyear'.encode('utf-8')
# Function to generate JWT
def generate_jwt():
header = b64url('{"alg":"HS256","typ":"JWT"}')
payload = b64url('{"sub":"1234567890","name":"John Doe","iat":1516239022}')
sig = b64url(hmac.new(
SECRET_KEY, (header + '.' + payload).encode('utf-8'), digestmod=sha256
).digest())
return header + '.' + payload + '.' + sig
# Function to verify JWT
def verify_jwt(token: str):
parts = token.split('.')
if len(parts) != 3:
return False
header, payload, received_sig = parts
new_sig = b64url(hmac.new(
SECRET_KEY, (header + '.' + payload).encode('utf-8'), digestmod=sha256
).digest())
return new_sig == received_sig
# Define the JWT verification dependency
class JWTBearer(HTTPBearer):
def __init__(self, auto_error: bool = True):
super(JWTBearer, self).__init__(auto_error=auto_error)
async def __call__(self, request):
credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
if credentials:
if not credentials.scheme == "Bearer":
raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
if not verify_jwt(credentials.credentials):
raise HTTPException(status_code=401, detail="Invalid or expired token.")
return credentials.credentials
else:
raise HTTPException(status_code=401, detail="Invalid authorization code.")
2. ログインインターフェイスの作成
# Simulated login interface
@app.post("/login")
def login():
token = generate_jwt()
return {"access_token": token, "token_type": "bearer"}
3. 保護されたインターフェイスの作成
# Protected interface
@app.get("/protected", dependencies=[Depends(JWTBearer())])
def protected_route():
return {"message": "This is a protected route."}
アプリケーションの実行
上記のコードを main.py
として保存し、ターミナルで以下のコマンドを実行してアプリケーションを起動します。
uvicorn main:app --reload
インターフェイスのテスト
-
ログインインターフェイス:
curl
やPostmanなどのツールを使用して、http://localhost:8000/login
にPOSTリクエストを送信すると、JWTが返されます。
curl -X POST http://localhost:8000/login
-
保護されたインターフェイス:返されたJWTを使用して、
http://localhost:8000/protected
にGETリクエストを送信し、リクエストヘッダーにAuthorization: Bearer <your_token>
を追加します。
curl -X GET http://localhost:8000/protected -H "Authorization: Bearer <your_token>"
まとめ
以上の手順を通じて、FastAPIでJWTを使った認証を行う方法を学びました。JWTは、ユーザーIDを安全かつ便利に管理する方法を提供し、分散型システム間の認証をより効率的にします。実際のアプリケーションでは、必要に応じてJWTの生成と検証ロジックを調整することができます。例えば、有効期限を追加したり、クレームをカスタマイズしたりすることができます。
Leapcell: The Best of Serverless Web Hosting
最後に、Pythonサービスのデプロイに最適なプラットフォームをおすすめします。Leapcell
🚀 好きな言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイ
使用した分だけ料金がかかり、リクエストがなければ料金はかかりません。
⚡ 従量制、隠れたコストは一切ありません
アイドル料金はなく、シームレスなスケーラビリティがあります。
🔹 Twitterでフォロー:@LeapcellHQ