🔥

🔐 FastAPI 実践入門:第五歩目で学ぶ認証・認可とセキュリティ対策

に公開

🧭 はじめに

FastAPIの基本とCRUD、RESTful API設計について学んだ後、次に重要なのは「セキュリティ」です。Webアプリケーションにおいては、ユーザー情報の保護、認証(Authentication)、認可(Authorization)は避けて通れない重要な要素です。
この記事では、FastAPIにおけるセキュアなAPI構築の基礎として、パスワードの暗号化、トークンベースの認証(JWT)、ログイン保護、ユーザーロールによるアクセス制限などを扱います。また、トークンの有効期限、エラーハンドリング、セキュリティ関連のベストプラクティスについても解説します。

🛡️ パスワードの安全な保存方法

パスワードをそのまま保存するのは極めて危険です。安全な方法としては「暗号化」ではなく、「ハッシュ化」を用いることが推奨されます。ハッシュ化されたパスワードは元に戻すことができず、漏洩時のリスクを大幅に下げることができます。

🔧 インストール

pip install passlib[bcrypt]

🧪 ハッシュ化の実装

from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def hash_password(password: str) -> str:
    return pwd_context.hash(password)

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

これにより、ユーザー登録時には hash_password() を使って安全に保存し、ログイン時には verify_password() を使って入力されたパスワードと照合できます。

🔑 JWT(JSON Web Token)を使った認証

ユーザーがログインした後、トークン(JWT)を発行して、それをもとにアクセス制限を行います。JWTは署名付きの情報で構成されており、トークン自体に必要なユーザー情報や有効期限を含めることができます。

📦 インストール

pip install python-jose[cryptography]

🔐 トークンの生成と検証

from jose import JWTError, jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

この create_access_token() 関数は、ユーザーIDなどの情報を含むセキュアなトークンを作成します。有効期限を設定することで、不正利用のリスクも減少します。

🚪 ログインエンドポイントの作成

以下のコードでは、OAuth2の仕組みを使って /token エンドポイントに対するPOSTリクエストでログイン認証を行い、JWTトークンを返します。

from fastapi import Depends, HTTPException, status, APIRouter
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

router = APIRouter()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")

@router.post("/token")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = create_access_token(data={"sub": user.username})
    return {"access_token": access_token, "token_type": "bearer"}

このルートを通じて、クライアントはユーザー名とパスワードを送信し、JWTを取得します。

🔍 認証付きルートの保護

発行したJWTを使って、APIルートにアクセス制限を設けます。

from fastapi import Depends
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        return username
    except JWTError:
        raise credentials_exception

@app.get("/users/me")
def read_users_me(current_user: str = Depends(get_current_user)):
    return {"username": current_user}

このようにして、保護されたルートに対しては有効なトークンを要求し、不正なアクセスをブロックできます。

🔒 ユーザーロールとアクセス制限

より高度な認可機能として、ユーザーにロール(役割)を割り当てることができます。たとえば、管理者(admin)だけがアクセスできるルートを定義することが可能です。

def get_current_active_admin(current_user: User = Depends(get_current_user)):
    if current_user.role != "admin":
        raise HTTPException(status_code=403, detail="Not enough privileges")
    return current_user

@app.get("/admin")
def read_admin_data(current_user: User = Depends(get_current_active_admin)):
    return {"admin_data": "Secret info"}

ユーザーのロールはデータベースに保存し、認証時に読み込んで検証します。こうした設計により、柔軟な権限管理が可能になります。
🧪 セキュリティにおけるテストとベストプラクティス

  • テスト環境では実際のSECRET_KEYを使用せず、モックを活用する
  • ログイン試行制限(レートリミット)を導入してブルートフォース攻撃を防止
  • HTTPS環境でのみトークンを扱うようにする
  • セキュリティヘッダー(CSP, X-Frame-Optionsなど)を追加する

これらを取り入れることで、より安全なFastAPIアプリケーションを構築できます。

🎯 まとめ

  • パスワードは必ずハッシュ化して保存し、プレーンテキストでは絶対に扱わない
  • JWTを使って安全なトークンベース認証を構築し、セッション管理を簡素化
  • FastAPIの Depends() を活用してセキュリティチェックをモジュール化・自動化
  • ユーザーロールを用いたアクセス制限により、柔軟な認可ロジックを構築
  • セキュリティのテストやベストプラクティスの導入で、堅牢なアプリケーションを目指す

株式会社ONE WEDGE

【Serverlessで世の中をもっと楽しく】 ONE WEDGEはServerlessシステム開発を中核技術としてWeb系システム開発、AWS/GCPを利用した業務システム・サービス開発、PWAを用いたモバイル開発、Alexaスキル開発など、元気と技術力を武器にお客様に真摯に向き合う価値創造企業です。
https://onewedge.co.jp/

Discussion