2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Middlewareを使ってBasic認証を設定できる

Next.jsのMiddlewareを使用することで、Basic認証をかけることができます。
本記事では、App RouterとPages RouterでのBasic認証のかけ方を紹介します。

Middleware とは

Next.jsにはMiddlewareという機能があり、リクエストが完了する前にコードを実行してリクエストを処理し、レスポンスを変更することができます。

Middlewareでの処理はリクエストごとに実行されるため、重たい処理を行うのには向いていませんが、Basic 認証などの軽い処理を行うのには適しています。

Middlewareは実行環境としてエッジランタイムが想定されており、Node.jsのfsなど一部APIが使用できない点に注意が必要です。

middlewareでfsを使用しようとすると以下のようなエラーが出ます。

⨯ The edge runtime does not support Node.js 'fs' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime

Basic 認証について

Basic 認証はHTTP認証方式の1つで、ユーザー名とパスワードを(Base64によってエンコードして)リクエストヘッダに付加して送信することで、認証を行います。
盗聴に弱くあまり安全な方法とは言えないため、セキュリティ上安全に使用するためには、HTTPS/TLSなど追加のセキュリティ強化機能が必要です。

Middleware を実装

Next.jsでMiddleware機能を使用ためには、middleware.tsmiddleware.js)という名前のファイルをapp(App Router)またはpages(Pages Router)と同階層に配置することで使用できます。

middleware.tsは1つのプロジェクトに1つまでしか配置できないことには注意が必要です。

それでは、Next.js公式のBasic認証実装例を見ていきたいと思います。

middleware.ts
import { NextRequest, NextResponse } from 'next/server'

export const config = {
  matcher: ['/', '/index'],
}

export function middleware(req: NextRequest) {
  const basicAuth = req.headers.get('authorization')
  const url = req.nextUrl

  if (basicAuth) {
    const authValue = basicAuth.split(' ')[1]
    const [user, pwd] = atob(authValue).split(':')

    if (user === '4dmin' && pwd === 'testpwd123') {
      return NextResponse.next()
    }
  }
  url.pathname = '/api/auth'

  return NextResponse.rewrite(url)
}

Basic認証の設定については以下のようになっています。

Basic認証を要求するパスの設定

export const config = {
  matcher: ['/', '/index'],
}

まず、configという定数でMiddlewareで処理を行うパスを設定できます。
この例では、//indexにアクセスした時にBasic認証が要求されることになります。

matcher: ['/:path*']などのように指定することで全てのパスに対してBasic認証をかけることもできます。

ユーザー名とパスワードの設定

if (user === '4dmin' && pwd === 'testpwd123') {
      return NextResponse.next()
    }

ユーザー名とパスワードは直書きせずに、.envファイル等での管理をおすすめします。

この箇所でリクエストヘッダから取得した(atobを使用してBase64でデコードした)ユーザー名とパスワードが正しいものか確認を行ないます。
ユーザー名とパスワードが正しく送られてきている場合には、NextResponse.next()によって、ルーティングの解決を続けます。

ユーザー名とパスワードが一致しない場合には、/api/authへリダイレクトされ、ユーザー名とパスワードの入力を要求します。

  url.pathname = '/api/auth'

  return NextResponse.rewrite(url)

次に、Basic認証の認証情報送信をクライアント側へ要求するために、/api/auth をどのように実装するかを、App RouterとPages Routerとで見ていきます。

App Router

App Routerでは、/app/api/auth/の下に以下のようなroute.tsファイルを配置します。

route.ts
import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(_: NextApiRequest, res: NextApiResponse) {
  res.setHeader('WWW-authenticate', 'Basic realm="Secure Area"')
  res.statusCode = 401
  res.end(`Auth Required.`)
}

Basic認証による認証が必要であることをレスポンスヘッダーに付加して返しています。

Pages Router

Pages Router では、pages/api/の下にauth.tsファイルを配置します。
(ファイルの内容はApp Routerの場合と同じです。)

auth.ts
import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(_: NextApiRequest, res: NextApiResponse) {
  res.setHeader('WWW-authenticate', 'Basic realm="Secure Area"')
  res.statusCode = 401
  res.end(`Auth Required.`)
}

開発モードでは認証を要求しない

開発中に認証情報を入力したくない場合には、NODE_ENVによる分岐を入れておくと快適です。

middleware.ts
import { NextRequest, NextResponse } from 'next/server'

export const config = {
  matcher: ['/:path*'],
}

export function middleware(req: NextRequest) {
     // 開発モードではBasic認証を要求しない
  if (process.env.NODE_ENV === 'development') {
    return NextResponse.next();
  }
  const basicAuth = req.headers.get('authorization')
  const url = req.nextUrl

  if (basicAuth) {
    const authValue = basicAuth.split(' ')[1]
    const [user, pwd] = atob(authValue).split(':')

  if (user === process.env.BASIC_AUTH_USER && pwd === process.env.BASIC_AUTH_PASSWORD) {
      return NextResponse.next()
    }
  }
  url.pathname = '/api/auth'

  return NextResponse.rewrite(url)
}
.env
BASIC_AUTH_USER='4dmin'
BASIC_AUTH_PASSWORD='testpwd123'

最後に

Middlewareを使うことでBasic認証を簡潔に設定できました。
他にも様々な処理を行えるので、積極的に活用していきたいですね。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?