阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈

在本文中,我將向您展示如何在使用身份驗證提供者時安全地將使用者資料備份到您自己的資料庫中。

什麼動圖

為什麼要先保留備份? 🤔

您是否曾經有意識地認為,當使用身份驗證提供者時,您實際上是在使用它們存儲用戶的訊息,並且您無權存取它們之外的用戶資料(甚至在您自己的資料庫中也無權存取)? 😳

身份驗證提供者的主要目的是抽像出使用者身份驗證邏輯,但這樣做時,您也將使用者的資料完全交給了他們,而您自己不保留任何控制權。

如果新實習生加入您的身分驗證提供者公司並錯誤地刪除了生產資料庫怎麼辦?這種情況極為罕見,但幾率也不是零。他們不僅會關閉他們的公司,而且您還會丟失所有用戶的資料。他們可能會設置一些備份來防止這種情況,但你永遠不知道另一家公司的幕後是如何實施的。

你們中的許多人甚至沒有想到這一點並開始使用其中一個提供者,只是因為它們更容易🤷‍♂️ 啟動和執行。

如果您正在使用一個,那麼我很確定您的資料庫中甚至沒有使用者表。我猜對了嗎? 🤨

震驚

如果您意識到這一點,那麼請繼續閱讀本文,我將向您展示如何安全地保留用戶資料的備份。


使用 Kinde 設定專案 🚀

ℹ️ 如果您已經有一個使用身分驗證提供者的專案,請隨意跳過本節。

我將向您展示範例Next.js應用程式中的一個範例,其中包含流行的身份驗證提供者之一,稱為Kinde

使用任何其他提供者時,步驟也將完全相同。

執行以下命令來引導具有TailwindEslintTypescript支援的新 Next.js 應用程式:

bunx create-next-app@latest --tailwind --eslint --typescript

上面的指令使用bun作為套件管理器。如果您還沒有安裝它,您可以繼續使用 npm、pnpm 或yarn。

設定 Kinde 身份驗證

確保使用以下命令安裝了必要的 kinde 軟體包:

bun i @kinde-oss/kinde-auth-nextjs

在 Kinde 中建立一個新專案,並將所有環境變數複製到專案中的.env檔案中。

KINDE_CLIENT_ID=<your_kinde_client_id>
KINDE_CLIENT_SECRET=<your_kinde_client_secret>
KINDE_ISSUER_URL=https://<your_kinde_subdomain>.kinde.com
KINDE_SITE_URL=http://localhost:3000
KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000
KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000/dashboard

請注意KINDE_POST_LOGIN_REDIRECT_URL變數。此變數可確保使用者在 Kinde 中通過驗證後,將被重新導向至/dashboard端點。

確保根據您的需求進行更改。我們的程式碼假設用戶成功登入後將被重新導向到/dashboard

現在,我們需要設定 Kinde Auth 路由器處理程序。在app/app/api/auth/[kindeAuth]/route.ts中,加入以下程式碼:

import {handleAuth} from "@kinde-oss/kinde-auth-nextjs/server";
export const GET = handleAuth();

這將設定必要的路由處理程序以將 Kinde 驗證新增至我們的應用程式。


設定資料庫模式🛠️

ℹ️ 我將使用 MongoDB 作為資料庫,使用 Prisma 作為 ORM。如果您喜歡任何其他 Prisma 替代品,例如 Drizzle 或 Mongoose,請隨意繼續使用它們。

執行以下命令將 Prisma 安裝為開發依賴項:

bun i prisma @prisma/client --save-dev

現在,使用以下命令初始化 Prisma:

bunx prisma init

執行此命令後,應在專案根目錄的prisma資料夾中建立新的schema.prisma檔案。

修改schema.prisma檔案以包含新的使用者模型。模型中的欄位可能會根據您的身分驗證提供者在成功建立使用者時提供的資訊而有所不同。

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model User {
  id       String  @id @map("_id") @db.String
  email    String  @unique
  username String  @unique
  name     String?

  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

// If you are adding this change on top of your exising Prisma Schema,
// you will have the rest of your models here...

現在我們已經準備好了模型,我們需要將其推送到資料庫中。為此,我們需要連接 URL。

如果您已有連線 URL,那就太好了。如果沒有,並且您正在繼續操作,請在MongoDB Atlas中建立新叢集並取得資料庫連接字串。然後,將一個名為DATABASE_URL的新變數以及連接字串值新增至.env檔案。

DATABASE_URL=<db-connection-string>

// Rest of the environment variables...

現在,我們需要設定PrismaClient ,我們可以用它來查詢資料庫。在/src/db目錄中建立一個新檔案index.ts其中包含以下程式碼行:

import { PrismaClient } from "@prisma/client";

declare global {
  // eslint-disable-next-line no-var
  var cachedPrisma: PrismaClient;
}

let prisma: PrismaClient;

if (process.env.NODE_ENV === "production") prisma = new PrismaClient();
else {
  if (!global.cachedPrisma) global.cachedPrisma = new PrismaClient();
  prisma = global.cachedPrisma;
}

export const db = prisma;

在開發環境中,程式碼初始化PrismaClient一次並全域快取以最佳化資源使用。在生產中,它會為每個請求建立一個新的PrismaClient實例。

執行以下命令將架構中的變更推送到資料庫。

bunx prisma db push

現在,要讓更新的類型在 IDE 中運作,請執行以下命令以根據更新的架構產生新類型。

bunx prisma generate

現在,這就是我們設定應用程式資料庫和身份驗證部分所需的全部內容。


設定備份📥

ℹ️ 到這一步我們所做的一切都是關於建立基本的專案結構。在本節中,我們將研究用戶首次在我們的應用程式中註冊後如何儲存用戶資訊的主要邏輯。

這就是用戶資料備份到我們的資料庫架構的樣子:

專案授權回調架構

每次新用戶註冊時,他們都會被重新導向到/dashboard頁面。在那裡,我們檢查該用戶是否存在於我們的資料庫中。如果沒有,它們將被重定向到/auth/callback端點,並在我們的資料庫中建立使用者。如果它們存在,則應用程式將照常繼續。

在根page.tsx檔案中新增以下程式碼行:

ℹ️ 我使用 Kinde 作為身分驗證提供者。檢查使用者驗證的程式碼會根據您使用的程式碼而有所不同,但邏輯應該是相同的。如果您按照步驟操作,請複製並貼上此程式碼。

"use client";

import {
  LoginLink,
  LogoutLink,
  useKindeBrowserClient,
} from "@kinde-oss/kinde-auth-nextjs";

export default function Home() {
  const { isAuthenticated } = useKindeBrowserClient();

  return (
    <main className="flex justify-center p-24">
      {!isAuthenticated ? (
        <LoginLink className="p-10 text-zinc-900 text-2xl font-semibold rounded-lg bg-zinc-100">
          Log in
        </LoginLink>
      ) : (
        <LogoutLink className="p-10 text-zinc-900 text-2xl font-semibold rounded-lg bg-zinc-100">
          Log out
        </LogoutLink>
      )}
    </main>
  );
}

這是我們應用程式的主頁,只有登入登出按鈕,這取決於使用者是否經過身份驗證。

使用者成功登入後,將被重新導向至/dashboard頁面。

/app/dashboard/page.tsx檔案中新增以下程式碼行:

import { db } from "@/db";
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";

const Page = async () => {
  const { getUser } = getKindeServerSession();
  const user = await getUser();

  if (!user?.id) redirect("/api/auth/login");

  const userInDB = await db.user.findUnique({
    where: {
      id: user.id,
    },
  });

  if (!userInDB) redirect("/auth/callback");

  return (
    <div className="flex flex-col justify-center items-center sm:mt-36 w-full mt-20">
      <h1 className="font-semibold text-zinc-900 text-2xl">
        You are authenticated
      </h1>
      <p className="font-medium text-xl text-zinc-700 text-center">
        The user has also been created in the DB
      </p>
    </div>
  );
};

export default Page;

我們檢查用戶是否經過身份驗證。如果沒有,我們會將使用者重新導向到 Kinde 登入頁面。

如果它們已通過身份驗證,但資料庫中不存在該用戶,我們會將它們重定向到/auth/callback端點,在該端點中,我們將使用當前登入的用戶詳細資訊在資料庫中建立一個新用戶。

/src/app/auth/callback/page.tsx中加入以下程式碼行:

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";
import { db } from "@/db";

const Page = async () => {
  const { getUser } = getKindeServerSession();
  const user = await getUser();

  if (!user?.id || !user?.email) redirect("/");

  const name =
    user?.given_name && user?.family_name
      ? `${user.given_name} ${user.family_name}`
      : user?.given_name || null;

  const userInDB = await db.user.findFirst({
    where: {
      id: user.id,
    },
  });

  if (!userInDB) {
    await db.user.create({
      data: {
        id: user.id,
        email: user.email,
        ...(name && { name }),
      },
    });
  }

  redirect("/dashboard");
};

export default Page;

在這裡,我們檢查用戶是否在我們的資料庫中。如果它們存在,我們將它們重新導向到/dashboard頁面。如果用戶不存在,我們將在資料庫中建立一個新用戶及其詳細訊息,然後重定向到/dashboard頁面。

就是這樣! 🎉 這些步驟確保身分驗證提供者中的使用者詳細資訊與我們的資料庫同步,而不僅僅是儲存在身分驗證提供者中。


包起來!

到目前為止,您已經大致了解了在使用身份驗證提供者時如何在自己的資料庫中備份使用者資訊。

本文的記錄原始碼可在此處取得:

https://github.com/shricodev/blogs/tree/main/auth-callback-auth-provider

非常感謝您的閱讀! 🎉🫡

在下面的評論部分寫下你的想法。 👇

https://linktr.ee/shricodev

在社交上關注我 ✌️

https://dev.to/shricodev


原文出處:https://dev.to/shricodev/do-this-first-if-you-are-using-an-auth-provider-1ndo


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。

阿川私房教材:學程式,拿 offer!

63 個專案實戰,直接上手!
無需補習,按步驟打造你的面試作品。

立即解鎖你的轉職秘笈