フルスタックチャンネル
サインアップサインアップ
ログインログイン
利用規約プライバシーポリシーお問い合わせ
Copyright © All rights reserved | FullStackChannel
解決済
「Next.js 13新機能のApp DirectoryとSupabaseでブログ構築」でユーザー登録後、詳細なプロフの作成画面へ強制リダイレクトを行いたい
Next.js
React
Node.js
ken
2023/07/05 12:01

実現したいこと

「Next.js 13新機能のApp DirectoryとSupabaseでブログ構築」でユーザー登録後、詳細なプロフィールの作成画面へ強制リダイレクトを行いたい

ソースコード

middleware.ts

import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'

import type { NextRequest } from 'next/server'
import type { Database } from '@/lib/database.types'

export async function middleware(req: NextRequest) {
  const res = NextResponse.next()
  const supabase = createMiddlewareClient<Database>({ req, res })

  const {
    data: { session },
  } = await supabase.auth.getSession()

  if (session) {
    const { data: currentProfile } = await supabase
      .from('profiles')
      .select('*')
      .eq('id', session.user.id)
      .single()

    if (currentProfile.register_status == 'TEMPORARY') {
      const redirectUrl = req.nextUrl.clone()
      redirectUrl.pathname = '/profile-detail'
      return NextResponse.redirect(redirectUrl)
    }
  }

  return res
}

また、このままだとDBへのリクエストが爆増してしまうので、
下記のようにLinkのprefetchをfalseにしました。

<Link
/*略*/
prefetch={false}
>

自分で試したこと

profilesテーブルにregister_statusカラムを追加し、登録時には値を"TEMPORARY"としておき、"TEMPORARY"の場合は
/profile-detailページ(詳細なプロフィール作成ページ)にリダイレクトを行いました。

補足情報

ログイン中は/profile-detailページに確実に飛ばすという処理にしたいのですが、
middleware.tsをこのように使用している事例が見当たりませんが、処理として問題ないでしょうか。

質問というより、野暮な相談となってしまいますが、よろしくお願いいたします。

回答 6件
login
回答するにはログインが必要です
ken
2年近く前

.

はる@講師
2年近く前

middlewareでsupabaseにアクセスするのはコストが高いので、register_statusをstoreの状態管理に保存しておき、middlewareでその状態を見てプロフィール画面に遷移する方針はいかがでしょうか?

よろしくお願い致します。

2
はる@講師
2年近く前

うまくいって良かったです。

引き続きよろしくお願いします。

ken
2年近く前

layout.tsxが読み込んでいるsupabase-listener.tsxから登録状態に応じてページを切り替えるようにしました。

ご回答いただきありがとうございました。

1
はる@講師
2年近く前

cookieでも動くと思いますが、なるべくcookieを使用せずに、工夫した方がいいですね。

middlewareではなく、layout.tsxで状態を判定する方法はいかがでしょうか。

layoutからでもうまく動作しない場合は、各コンポーネントでリダイレクトするようにしたら、うまくいくかと思います。

1
ken
2年近く前

ご回答いただきありがとうございます。すぐにご回答いただいたにも関わらず、レスが遅くなり恐縮です。

私のやり方が悪いのか、zustandだとmiddleware.tsから値を読み込めませんでした。

代替手段として、navigation.tsからDBの値に応じてcookieでregister_statusを設定し、cookieの値に応じてmiddlewareからリダイレクトする方法を採用しました。

予期しないリダイレクトが発生しないようにログイン後最初に訪れるルートURLの場合にのみ、本登録画面(/profile-detail)にリダイレクトするようにしました。

こちらの処理は違和感ありますでしょうか。修正すべきところがあれば、ご教授いただけると幸いでございます。

ソースコード

Next.jsのドキュメントが最新版となっておりcookie関係の古いAPIの引数が調査できなかったため、Next.jsを最新にしました

npm install next@13.4.7

server actionでcookieを設定する方法がうまくいかなかったので、cookieの値をセット(name: register_status value:TEMPORARY)するAPIを用意しました。

set-cookie/route.ts

import { cookies } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
  const cookieStore = cookies()

  try {
    cookieStore.set({
      name: 'register_status',
      value: 'TEMPORARY',
      secure: true,
    })
    return NextResponse.json({ response: 'OK' })
  } catch (error) {
    console.log('error', error)
    return NextResponse.error()
  }
}

navigation.tsxでステータスに応じて前述したAPIを呼び出すようにしました。

navigation.tsx

/* 略 */ 
  useEffect(() => {

    setUser({/* 略 */}) 

    //追記
    if (session && profile.register_status == 'TEMPORARY') {
      const fn = async () => {
        try {
          const res = await axios.get('/api/set-cookie', {})
        } catch (error) {
          console.log(error)
        } finally {
        }
      }
      fn()
    }
  }, [session, setUser, profile])
/* 略 */ 

middleware側でcookieの値をみてルートへのアクセスをリダイレクトするようにしました。

middleware.ts

import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'

import type { NextRequest } from 'next/server'
import type { Database } from '@/lib/database.types'

export const config = {
  matcher: [
    /*
     * Match all paths except for:
     * 1. /api routes
     * 2. /_next (Next.js internals)
     * 3. /examples (inside /public)
     * 4. all root files inside /public (e.g. /favicon.ico)
     */
    '/((?!api/|_next/|_static/|examples/|[\\w-]+\\.\\w+).*)',
  ],
}

export async function middleware(req: NextRequest) {
  const res = NextResponse.next()
  const supabase = createMiddlewareClient<Database>({ req, res })
  const session = await supabase.auth.getSession()

  if (session) {
    if (
      req.cookies.get('register_status')?.value == 'TEMPORARY' &&
      req.nextUrl.pathname == '/'
    ) {
      const redirectUrl = req.nextUrl.clone()
      redirectUrl.pathname = '/profile-detail'
      return NextResponse.redirect(redirectUrl)
    }
  }

  return res
}