Next.js 12.2のMiddlewareでSupabaseのauth-helpersのwithMiddlewareAuthを使う
withMiddlewareAuthを使うと認証しているユーザーに絞ってアクセスの可否をサーバー側で判定することができます。認証していないユーザーについては指定URLにリダイレクトするなどの対策ができます。
Next.js 12.2からMiddlewareの書き方が変わってしまったので備忘録としてまとめます。
import type { NextRequest } from "next/server";
import { withMiddlewareAuth } from "@supabase/auth-helpers-nextjs/dist/middleware";
export const middleware = withMiddlewareAuth({
redirectTo: "/login",
});
export const config = {
matcher: "/shops/:path*",
};
matcher
は対象URLを指す。
この例の場合は http://example.com/shops
自身を含みつつ配下が対象となります。つまり、 http://example.com/shops
はもちろん、 http://example.com/shops/hogehoge
や http://example.com/shops/pagepage
などが対象になります。
配下じゃなくて、指定した階層だけを制限したい場合( http://example.com/shops
だけを対象にする )は、matcher: "/shops/"
とするだけでOK。
公式ドキュメント:
※ import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/middleware';
としている箇所があるが、 現状では import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs/dist/middleware';
に移動してるっぽいので注意
ログイン中のユーザーでパーミッションを絞ることもできるらしい。
export const middleware = withMiddlewareAuth({
redirectTo: '/login',
authGuard: {
isPermitted: async (user) => user.email?.endsWith('@example.com') ?? false,
redirectTo: '/insufficient-permissions'
}
});
この例の場合、メールアドレスの末尾が @example.com
だけがアクセスできるんだと思う。
ということはSNS認証しつつメールアドレスを ===
なときだけアクセスできるようにすれば激強ガード作れるんじゃない?知らん
import { withMiddlewareAuth } from "@supabase/auth-helpers-nextjs/dist/middleware";
export const middleware = withMiddlewareAuth({
redirectTo: "/login",
authGuard: {
isPermitted: async (user) =>
user.email === "hogehoge@example.jp" ?? false,
},
});
実際にやってみた。この場合 hogehoge@example.jp のユーザー以外はアクセスできなくなります。Supabaseではメールアドレスを重複して取得はできませんから、強固なものになるかと思います。(各サービスのルールに縛られることになるので。それを突破できない限りはそのデータを渡すことすらできない訳で。)
もっと強くするには条件を追加すると良いかもしれません。
export const middleware = withMiddlewareAuth({
redirectTo: "/login",
authGuard: {
isPermitted: async (user) =>
(user.email === "hogehoge@example.jp" &&
user.app_metadata.provider === "twitter" &&
user.user_metadata.full_name === "hoge") ??
false,
},
});
※getServerSidePropsでuserの値をconsole.logしてサーバー側で確認した値を使っています。管理者を強固に固定する場合には向いてるかも?
ちなみに、2022年8月1日の時点ではNext.js12.2系には未対応なのでNext.js12.1.6などを暫定的に使うといいと思います。