我正尝试将用户身份验证添加到我的NextJS项目中的每个页面(页面,而不是应用程序)。本教程非常有帮助(也正是我想做的)-https://alexsidorenko.com/blog/next-js-protected-routes/-但我在将Supabase的默认身份验证UI和功能集成到该模型(https://supabase.com/docs/guides/auth/auth-helpers/nextjs)中时遇到了麻烦。
我的基本目标是将身份验证分支转移到_app. tsx中,而不是转移到每个页面上:
// _app.tsx
import { useEffect, useState } from "react";
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { SessionContextProvider, useUser, useSession, useSupabaseClient, Session } from '@supabase/auth-helpers-react'
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
import { AppProps } from 'next/app'
import { UserContext } from "@components/user"
function MyApp({Component, pageProps}: AppProps<{ initialSession: Session }>) {
const [supabase] = useState(() => createBrowserSupabaseClient())
const session = useSession()
const user = useUser()
console.log("session:" + session);
console.log("user:" + user);
useEffect(() => {
if (
pageProps.protected
) {
return <Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
}
}, [])
return (
<SessionContextProvider supabaseClient={supabase} session={session} initialSession={pageProps.initialSession}>
<Component {...pageProps} />
</SessionContextProvider>
)
}
export default MyApp
要保护的页面(例如,索引页)如下所示:
// index.tsx
import Account from "@components/account";
const Home = () => {
return (
<div>
<Account session={session} />
</div>
)
}
export async function getStaticProps(context) {
return {
props: {
protected: true,
},
}
}
export default Home
索引页面上包含的Account组件是Supabase即用型配置文件面板,但它可以是任何内容:
// @components/account.tsx
import { useState, useEffect } from 'react'
import { useUser, useSupabaseClient, Session } from '@supabase/auth-helpers-react'
import { Database } from '@utils/database.types'
type Profiles = Database['public']['Tables']['profiles']['Row']
export default function Account({ session }: { session: Session }) {
const supabase = useSupabaseClient<Database>()
const user = useUser()
const [loading, setLoading] = useState(true)
const [username, setUsername] = useState<Profiles['username']>(null)
useEffect(() => {
getProfile()
}, [session])
async function getProfile() {
try {
setLoading(true)
if (!user) throw new Error('No user')
let { data, error, status } = await supabase
.from('profiles')
.select(`username`)
.eq('id', user.id)
.single()
if (error && status !== 406) {
throw error
}
if (data) {
setUsername(data.username)
}
} catch (error) {
alert('Error loading user data!')
console.log(error)
} finally {
setLoading(false)
}
}
async function updateProfile({
username,
}: {
username: Profiles['username']
}) {
try {
setLoading(true)
if (!user) throw new Error('No user')
const updates = {
id: user.id,
username,
updated_at: new Date().toISOString(),
}
let { error } = await supabase.from('profiles').upsert(updates)
if (error) throw error
alert('Profile updated!')
} catch (error) {
alert('Error updating the data!')
console.log(error)
} finally {
setLoading(false)
}
}
return (
<div>
<div>
<label htmlFor="email">Email</label>
<input id="email" type="text" value={session.user.email} disabled />
</div>
<div>
<label htmlFor="username">Username</label>
<input id="username" type="text" value={username || ''} onChange={(e) => setUsername(e.target.value)} />
</div>
<div>
<button onClick={() => updateProfile({ username })} disabled={loading} >
{loading ? 'Loading ...' : 'Update'}
</button>
</div>
<div>
<button onClick={() => supabase.auth.signOut()}>
Sign Out
</button>
</div>
</div>
)
}
我想我对protected routes和Supabase对session和user的使用之间的关系有一个根本性的误解。
任何帮助都将不胜感激。
1条答案
按热度按时间v440hwme1#
我建议使用Next.js中间件来实现这一点:https://supabase.com/docs/guides/auth/auth-helpers/nextjs#auth-with-nextjs-middleware