Fresh で特定のページのみ Basic 認証を動かしたい

Dec 9th, 2022 typescript deno fresh

状況

解決策

Fresh には middleware 機能が存在する.これを用いてルーティングの範囲を絞って認証を動かすことができる.

参考: https://fresh.deno.dev/docs/concepts/middleware

下記のようなルーティングを考える(ルーティング以外は省略).

.
└── routes
    ├── admin
    │   ├── [id].ts
    │   └── index.ts
    ├── [name].tsx
    ├── api
    │   └── joke.ts
    └── index.tsx

admin 以下のルートに認証をかけたいとする場合,admin 以下に _middleware.ts を作成し,以下の内容を記述する.

// routes/admin/_middleware.ts

import { MiddlewareHandlerContext } from "$fresh/server.ts";

interface State {
  data: string;
}

export async function handler(
  req: Request,
  ctx: MiddlewareHandlerContext<State>,
) {
  // 🔽ユーザ名とパスワードを設定
  const user = "admin";
  const password = "password";

  // 🔽 認証を動かすコード
  if (
    req.headers.get("Authorization") !== `Basic ${btoa(`${user}:${password}`)}`
  ) {
    const headers = new Headers({
      "WWW-Authenticate": 'Basic realm="Fake Realm"',
    });
    return new Response("Unauthorized", { status: 401, headers });
  }
  ctx.state.data = "myData";
  const resp = await ctx.next();
  resp.headers.set("server", "fresh server");
  return resp;
}

このようにすることで,admin ディレクトリ以下のみで認証を動かすことができる.

同様に他のルーティングでもディレクトリを分けることで別々の middleware ファイルを動かして,異なるユーザ名とパスワードで認証を動かすことができる.

まとめ

以上だ( `・ω・)b