【Next.js】middlewareでベーシック認証やってみる
概要
前回でNext.jsでMiddlewareについて勉強してみたらやってみたくなるのがベーシック認証。
という事で今回はベーシック認証をやってみる。
最終目的
最終的には、トップページからAboutページに移動した場合にベーシック認証を求められる。
入力して合っていた場合は、Aboutページを表示して、間違っていた場合は、「Auth Required」と表示させる。
実装
実装にあたって、まずはプロジェクトを立ち上げる。
とりあえずtypescript
にしておきます。
npx create-next-app basic-auth-app --typescript
設置場所
前回、説明しているが、middlewareはルートディレクトリに設置している。
- pages/api/auth.ts
- pages/index.ts
- pages/about.ts
- middleware.ts
- .env
環境変数(.env
)ファイルはベーシック認証に必要なユーザー名とパスワードを記載しておく為のファイル。
.env
とmmiddleware.ts
はルートディレクトリに設置しています。
.envファイル
環境変数(.env
)のサポートはバージョン 9.4 以上の Next.js から組み込まれています。
まずは.env
ファイルです。適当に下記のようにしました。
USER=hogehoge
PASSWORD=fugafuga
呼び出すには以下のようにprocess.env.環境変数名となる。
process.env.USER
process.env.PASSWORD
middleware.ts
今度はmiddleware.ts
について。
import { NextRequest, NextResponse } from 'next/server'
//Aboutページだけにベーシック認証を設定
export const config={
matcher:"/about"
}
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===process.env.USER && pwd === process.env.PASSWORD){
return NextResponse.next()
}
}
url.pathname="/api/auth"
return NextResponse.rewrite(url)
}
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`)
}
トップページとAboutページ
こちらについては、通常のページなのでシンプルにしています。
import type { NextPage } from 'next'
import Link from 'next/link'
const Home: NextPage = () => {
return (
<div>
<h1>トップページ</h1>
<Link href="/about">Aboutページ</Link>
</div>
)
}
export default Home
Aboutページも同様です。
import type { NextPage } from 'next'
const About:NextPage = () => {
return (
<div>
<h1>About</h1>
</div>
);
};
export default About;
動作確認
上記のコードを書いて実行すると以下のようになる。
ベーシック認証を求められる画面
失敗した画面
成功したらAboutページに移動する
べーシンク認証の流れ
上記のコードの流れは以下のような処理になっている(はず)。
- トップページからAboutページへ移動
- Aboutページの前にmiddlewareを実行する。
- middlewareでhttpリクエストのヘッダを見て、Authorizationというヘッダーを確認
- 最初は設定されていない(null)ので、auth.tsを実行する
- auth.tsではWWW-AuthenticateにBasic realm="値"というヘッダがセットされた401レスポンスを受け取ったら、IDとPASSWORDを入力するダイアログを表示する。
- ユーザはIDとPASSWORDを入力する。
- ブラウザは入力された値をAuthrizationヘッダに設定したあと、再度middlewareを実行
- Authorizationヘッダを解析して正しいIDとパスワードが設定されているかを確認する。
- envファイルに設定されてる値と入力された値が一致したら、Aboutページへ移動
上記の流れを確認するためにmiddleware.ts
とauth.ts
にconsole.log
で確認すると流れが分かりやすいかも。
export function middleware(req:NextRequest){
const basicAuth=req.headers.get('authorization')
const url=req.nextUrl
console.log("middlwware実行")
console.log("authorization:"+basicAuth)
if(basicAuth){
const authValue=basicAuth.split(" ")[1]
console.log("authValue")
console.log(authValue)
//ユーザー名とPWDを取り出す
const [user,pwd]=atob(authValue).split(":")
console.log(user,process.env.USER)
console.log(pwd,process.env.PASSWORD)
}
}
export default function handler(_:NextApiRequest,res:NextApiResponse){
console.log("auth.ts")
}
それぞれconsole.log
を実行してみて実際に流れをみると、以下のように出力されます。
最初にAboutページへ移動した時
ベーシック認証を求められて入力したが一致しなかった場合
一致しなかった場合は再度、auth.ts
を実行している
ユーザー名とパスワードを入力して一致した場合
一致した場合は、NextResponse.next()
でAboutページへ移動してるのでauth.ts
は実行されず
まとめ
ベーシック認証をやってみたけど、割とこれはテンプレのような気がするな。
以下のサイトが参考になりました。ありがとうございます。
Discussion