Closed4

Next.js 12.2のMiddlewareでSupabaseのauth-helpersのwithMiddlewareAuthを使う

masa5714masa5714

withMiddlewareAuthを使うと認証しているユーザーに絞ってアクセスの可否をサーバー側で判定することができます。認証していないユーザーについては指定URLにリダイレクトするなどの対策ができます。

masa5714masa5714

Next.js 12.2からMiddlewareの書き方が変わってしまったので備忘録としてまとめます。

middleware.ts
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/hogehogehttp://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'; に移動してるっぽいので注意
https://github.com/supabase-community/auth-helpers/blob/main/packages/nextjs/README.md

masa5714masa5714

ログイン中のユーザーでパーミッションを絞ることもできるらしい。

middleware.ts
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/08/11にクローズされました