我的背景来自React+Python Flask应用程序。我现在正在将网站转换为 Next.js,无需使用 Python Flask 应用程序。
该网站将使用 Next.js v15 创建。 目前我正在实现 Auth.js v5。
我的用户可以使用 Google 登录,效果很好。
我的问题是,当我有一个带有
"use client";
的页面时,如何检查用户是否已登录。
例如,我有一个页面 app/(private)/customers/page.tsx
,其中显示使用客户端组件的客户列表。
应用程序/(私人)/客户/page.tsx
例如,我有一个名为
app/(private)/customers/page.tsx
的页面,它使用 "use client";
。如何在此页面检查用户是否已登录?
// app/(private)/customers/page.tsx
"use client";
import { authConfig } from "@/app/lib/auth";
import { loginRequiredClient } from "@/app/lib/loginRequiredClient";
import { getServerSession } from "next-auth";
import Link from "next/link";
import useSWR from "swr";
export default async function Dashboard() {
// Get my user
await loginRequiredClient();
const session = await getServerSession(authConfig);
// Get customers
const { data: customersData, error: customersError, isLoading: customersIsLoading } = useSWR("/customers/api-customers/api-get-customers/");
if (customersError) return <div className="error_smal"><span>Failed to load</span></div>;
if (customersIsLoading) return ( <div><div className="loading"></div><span>Loading...</span></div> );
// Return
return (
<>
<h1>Customers</h1>
<ul>
{customersData?.data.map((customer: CustomerI) => (
<li className="list-none" key={customer.customer_id}>
<p>{customer.customer_name}</p>
</li>
))}
</ul>
</>
);
}
应用程序/(私人)/客户/api-customers/api-get-customers/route.ts
// app/(private)/customers/api-customers/api-get-customers/route.ts
import { authConfig } from "@/app/lib/auth";
import { sql } from "@/app/lib/db";
import { loginIsRequiredServer } from "@/app/lib/loginIsRequiredServer";
import { getServerSession } from "next-auth";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
// Get my user
await loginIsRequiredServer();
const session = await getServerSession(authConfig);
// Fetch customers from database
const res = await sql(
`SELECT customer_id, customer_name FROM customers_index
ORDER BY customer_name ASC;`
);
return NextResponse.json({ data: res.rows });
}
应用程序/lib/auth.ts
// app/lib/auth.ts
import { NextAuthOptions, User, getServerSession } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import { sql } from "./db";
export const authConfig: NextAuthOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_OAUTH_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET as string,
})
],
callbacks: {
async signIn({ user }) {
// Check if user exists in the database
const res = await sql(
"SELECT user_id, user_first_name, user_middle_name, user_last_name FROM c_users_index WHERE user_email=$1",
[user.email]
);
if (res.rowCount == 0) {
// User does not exist
console.log(`app/lib/auth.ts::authConfig()::User not found ${user.email}`);
return false;
}
const sqlMyUser = res.rows[0]
// User exists
return true;
},
async session({ session, user }) {
// Add additional properties to the session here if needed
return session;
}
}
};
app/lib/loginIsRequiredServer.ts
// app/lib/loginIsRequiredServer.ts
import { getServerSession } from "next-auth";
import { authConfig } from "./auth";
import { redirect } from "next/navigation";
export async function loginIsRequiredServer() {
const session = await getServerSession(authConfig);
if (!session) return redirect("/");
}
应用程序/lib/loginRequiredClient.ts
// app/lib/loginRequiredClient.ts
"use client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
// Custom hook to check if login is required
export function loginRequiredClient() {
const session = useSession();
const router = useRouter();
if (typeof window !== "undefined" && !session) {
router.push("/");
}
}
应用程序/lib/db.ts
// app/lib/db.ts
import { Client, QueryResult } from "pg";
import { loadEnvConfig } from "@next/env";
const projectDir = process.cwd();
loadEnvConfig(projectDir)
// Generate a Postgres client
export async function getClient(): Promise<Client>{
// console.log("db.ts::getClient()::Init");
// Client with URL
if (process.env.DB_URL) {
// console.log("db.ts::getClient()::Connecting client with URL"); // + "?sslmode=require"
const client = new Client({
connectionString: process.env.DB_URL,
});
// console.log("db.ts::getClient()::Connecting client with URL [connected]");
return client;
}
// Client with username, host, database, password
// console.log("db.ts::getClient()::Connecting client with username, host, database, password");
const client = new Client({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASS,
port: parseInt(process.env.DB_PORT!)
});
// console.log("db.ts::getClient()::Connecting client with username, host, database, password [connected]");
return client;
}
// Handle connection, SQL and end the connection
export async function sql(sql: string, values?: Array<any>): Promise<QueryResult<any>> {
// console.log("db.ts::sql()::Querying");
const client = await getClient();
await client.connect();
// console.log("db.ts::sql()::Querying Connect");
const res = await client.query(sql, values);
// console.log("db.ts::sql()::Querying Await client query");
await client.end();
// console.log("db.ts::sql()::Querying [OK]");
return res;
}
首先,您必须使用
SessionProvider
包装整个应用程序根目录或所需的应用程序根目录(即layout.tsx)
import { SessionProvider } from "next-auth/react";
import type { ReactNode } from "react";
interface LayoutProps {
children: ReactNode;
}
export default async function Layout({ children }: LayoutProps) {
return (
<SessionProvider>
{children}
</SessionProvider>
);
}
然后在您的客户端页面中
"use client"
import { useSession } from "next-auth/react"
import { UserAvatar } from "@/components/UserAvatar"
export default function Dashboard() {
const session = useSession()
return (
<div>
{JSON.stringfy(session)}
</div>
)
}
您可以检查会话是否为空。