「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をこのように使用している事例が見当たりませんが、処理として問題ないでしょうか。
質問というより、野暮な相談となってしまいますが、よろしくお願いいたします。
middlewareでsupabaseにアクセスするのはコストが高いので、register_statusをstoreの状態管理に保存しておき、middlewareでその状態を見てプロフィール画面に遷移する方針はいかがでしょうか?
よろしくお願い致します。
うまくいって良かったです。
引き続きよろしくお願いします。
layout.tsxが読み込んでいるsupabase-listener.tsxから登録状態に応じてページを切り替えるようにしました。
ご回答いただきありがとうございました。
cookieでも動くと思いますが、なるべくcookieを使用せずに、工夫した方がいいですね。
middlewareではなく、layout.tsxで状態を判定する方法はいかがでしょうか。
layoutからでもうまく動作しない場合は、各コンポーネントでリダイレクトするようにしたら、うまくいくかと思います。
ご回答いただきありがとうございます。すぐにご回答いただいたにも関わらず、レスが遅くなり恐縮です。
私のやり方が悪いのか、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
}