Next.js 与 Typescript 和 Auth.js v5 - 如何确保用户登录到使用“使用客户端”的页面?

问题描述 投票:0回答:1

我的背景来自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;
}
next.js auth.js
1个回答
0
投票

首先,您必须使用

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>
  )
}

您可以检查会话是否为空。

© www.soinside.com 2019 - 2024. All rights reserved.