LoginSignup
5
3

More than 1 year has passed since last update.

FastAPIでBasic認証

Last updated at Posted at 2022-04-19

公式情報

片方だけでいい場合は、公式の実装をそのまま利用すればよい。この記事では、両方にBasic認証をかけてみる。

API/static filesそれぞれにBasic認証を実装する

Basic認証用のモジュール

id/passは環境変数で指定する想定

basic_auth.py
import secrets
import os

from fastapi import HTTPException, status, Request, Depends
from fastapi.staticfiles import StaticFiles
from fastapi.security import HTTPBasic, HTTPBasicCredentials

security = HTTPBasic()


def auth_basic(credentials: HTTPBasicCredentials):
    correct_username = secrets.compare_digest(
        credentials.username, os.environ.get("BASIC_USER"))
    correct_password = secrets.compare_digest(
        credentials.password, os.environ.get("BASIC_PASSWORD"))
    if not (correct_username and correct_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Basic"},
        )


def verify_from_api(credentials: HTTPBasicCredentials = Depends(security)):
    auth_basic(credentials)


class AuthStaticFiles(StaticFiles):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

    async def __call__(self, scope, receive, send) -> None:
        assert scope["type"] == "http"

        request = Request(scope, receive)
        credentials = await security(request)
        auth_basic(credentials)
        await super().__call__(scope, receive, send)

Basic認証用のモジュールを利用してコントローラを実装

from fastapi import FastAPI, HTTPException, status, UploadFile, File, Request, Depends
from basic_auth import verify_from_api, AuthStaticFiles

app = FastAPI()
app.mount("/static", AuthStaticFiles(directory="static"), name="static")


@app.get("/api/me")
def me(_ = Depends(verify_from_api)):
    return {"message": "authorized"}

コードの解説

security = HTTPBasic()

credentials = await security(request)

auth_basic(credentials)

  • ここでユーザ名・パスワードの認証を行う
  • 実体はこんな感じ correct_username = secrets.compare_digest(credentials.username, os.environ.get("BASIC_USER"))
  • secrets.compare_digest は、タイミング攻撃を防ぐような安全な文字列比較メソッド
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3