採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

L14 ch02 — 認証 (JWT)

テクノロジ系 / L14 middleware — ミドルウェア

L14 ch02 — 認証 (JWT)

「誰がアクセスしているか」を毎リクエスト判定する最小例

ゴール

  • JWT (JSON Web Token) の役割を理解
  • ログインで token を発行できる
  • 保護されたエンドポイントを Authorization ヘッダで認証できる

なぜ認証が必要か

HTTP は ステートレス = 毎リクエスト「誰か」が分からない

GET /tasks   ← これ、誰のタスク?

→ クライアントが毎回「私は X です」と証明する必要がある

→ 証明書代わりに token を渡す

JWT (JSON Web Token) とは

文字列 1 本で「ユーザー情報 + 改ざん防止署名」を表現する規格

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0YXJvIn0.signatureXYZ
└── header ──┘ └── payload (誰か) ─┘ └── 署名 ─┘
  • payload に user_id などを入れる
  • 秘密鍵で署名 → 改ざんされたら検証で弾ける
  • Cookie / セッション DB が不要 (= ステートレス API 向き)

認証の流れ

[1] POST /login {user, password}
        ↓
    サーバー: 認証成功 → JWT を発行して返す

[2] GET /me   Authorization: Bearer <JWT>
        ↓
    サーバー: JWT を検証 → ユーザー特定 → レスポンス

最小例: token 発行

from datetime import datetime, timedelta, timezone
import jwt   # PyJWT

SECRET = "demo-secret-key"   # 本番では環境変数
ALGO = "HS256"

def create_token(username: str) -> str:
    payload = {
        "sub": username,
        "exp": datetime.now(timezone.utc) + timedelta(hours=1),
    }
    return jwt.encode(payload, SECRET, algorithm=ALGO)

最小例: token 検証

from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer

oauth2 = OAuth2PasswordBearer(tokenUrl="login")

def current_user(token: str = Depends(oauth2)) -> str:
    try:
        payload = jwt.decode(token, SECRET, algorithms=[ALGO])
        return payload["sub"]
    except jwt.PyJWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

エンドポイントに繋ぐ

@app.post("/login")
def login(username: str, password: str):
    # ※デモ: パスワード固定。本番は DB + ハッシュ照合
    if password != "secret":
        raise HTTPException(status_code=401, detail="Bad credentials")
    return {"access_token": create_token(username), "token_type": "bearer"}

@app.get("/me")
def me(user: str = Depends(current_user)):
    return {"user": user}

リクエスト例

# 1. ログインして token を取得
curl -X POST "http://localhost:8000/login?username=taro&password=secret"
# → {"access_token":"eyJhbGc...","token_type":"bearer"}

# 2. token を付けて保護エンドポイントを叩く
curl http://localhost:8000/me \
  -H "Authorization: Bearer eyJhbGc..."
# → {"user":"taro"}

やってはいけないこと

NG理由
SECRET をコードに直書き (本番)git に漏れる → 全 token が偽造可能
exp (有効期限) を入れない一度漏れた token が永久に使える
パスワードを平文で DB 保存漏洩時に致命的 (bcrypt 等でハッシュ化)
token を URL のクエリに付けるログに残る → 漏洩リスク (ヘッダで送る)

drill

drill/ — fill-jwt

create_token / current_user___ を埋めて JWT 認証を完成させる

よくある詰まり

症状原因対処
401 Invalid tokenSECRET / アルゴリズムが不一致encode と decode で揃える
ExpiredSignatureErrorexp を過ぎた再ログインで再発行
KeyError: 'sub'payload に sub を入れていないencode 側で "sub": username

次に学ぶ領域

領域続けて読む
パスワードのハッシュ化passlib[bcrypt] (= security/ch01)
Refresh token / token 失効上位章 (本教材スコープ外)
OAuth2 連携 (Google など)fastapi.security の他のクラス
力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。