Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Redis

Tạo Hệ Thống Bình Luận An Toàn Cho Blog Next.js Với Redis & NextAuth

Chúng ta xây dựng comment section cho blog trong tutorial này️. Tech stack:

  1. NextJS 13 (App dir)
  2. NextAuth (Authentication)
  3. Upstash Redis (lưu comments)
  4. SWR (Caching và Revalidation comments)

Bắt đầu.

Xử Lý Auth Với NextAuth

Trước hết, không thể cho bất kỳ ai post comment, đúng không? Ai đó có thể chạy script spam comment blog bạn. Xây dựng hệ thống Authentication trước khi cho post comment. Dùng NextAuth.

Cài next-auth trong project.

pnpm install next-auth

Cấu trúc thư mục trong App Directory:

. ├── app
│ ├── api
│ │ └── auth
│ │ └── [...nextauth]
│ │ └── route.ts
│ ├── blog
│ │ ├── page.tsx
│ │ └── [...slug]
│ │ └── page.tsx
│ ├── components
│ │ └── LoginButton.tsx
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx 

Setup Auth API route:

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
const handler = NextAuth({
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async session({ session, token }) {
      if (session && session.user && token.sub) {
        session.user.sub = token.sub;
      }
      return session;
    },
  },
});
export { handler as GET, handler as POST };

Tạo Github OAuth application mới từ đây lấy GITHUB_CLIENT_ID và GITHUB_CLIENT_SECRET.

Tạo Hệ Thống Bình Luận An Toàn Cho Blog Next.js Với Redis & NextAuth

NextAuth cho phép Sign in và SignOut từ bất kỳ Client Component nào dùng function signIn và signOut từ next-auth. Trước đó, setup Context Provider wrap toàn bộ ứng dụng.

// app/layout.tsx
"use client";
import "./globals.css";
import { SessionProvider } from "next-auth/react";
export default function RootLayout({ children, }: { children: React.ReactNode; }) {
  return (
    <html lang="en">
      <SessionProvider>
        <body>{children}</body>
      </SessionProvider>
    </html>
  );
}

SessionProvider cho phép truy cập session state từ bất kỳ Client component nào.

Truy cập session state dùng hook useSession từ next-auth. Sample Login Button:

"use Client";
import { signIn, signOut, useSession } from "next-auth/react";
export default function LoginButton() {
  const { data: session } = useSession();
  if (session) {
    return (
      <div>
        Signed in as {session.user?.name} using {session.user?.email}
        <br />
        <button onClick={() => signOut()}>Sign out</button>
      </div>
    );
  }
  return (
    <div>
      Not signed in
      <br />
      <button onClick={() => signIn()}> Sign in </button>
    </div>
  );
}

Với này, Auth system ready. Bây giờ bắt đầu server-side routes lưu comment trong Redis database.

Thiết Lập Redis Database

  1. Vào Upstash tạo Redis Database.
  2. Chọn region gần user và bật TLS encryption.
  3. Cài package @upstash/redis.
pnpm install @upstash/redis

Tạo Hệ Thống Bình Luận An Toàn Cho Blog Next.js Với Redis & NextAuth

  1. Copy tokens vào .env.local.

Viết API endpoints trong cấu trúc thư mục:

. ├── app
│ ├── api
│ │ ├── auth
│ │ │ └── [...nextauth]
│ │ │ └── route.ts
│ │ ├── comment
│ │ │ ├── delete
│ │ │ │ └── route.ts
│ │ │ ├── get
│ │ │ │ └── route.ts
│ │ │ └── post
│ │ │ └── route.ts
│ │ └── lib
│ │ ├── getUser.ts
│ │ └── redis.ts 
  1. Tạo Redis Client Instance
// app/api/lib/redis.ts
import { Redis } from "@upstash/redis";
/* Thử load UPSTASH_REDIS_REST_URL và UPSTASH_REDIS_REST_TOKEN từ environment dùng process.env */
const redis = Redis.fromEnv();
export default redis;

Đó là xong. Redis Client setup xong, chỉ còn setup API routes cho nó trong ứng dụng.

Dùng Redis Lists lưu comments. Chúng act như stack nên comment mới nhất hiển thị top. Chắc chắn có thể implement sorting logic client-side nhưng Redis đã cung cấp data structure này, dùng nó.

Xem toàn bộ code tại đây. Tóm tắt:

  1. Tạo comment: redis.lpush(referer, comment). Push comment vào list có key referer

  2. Lấy tất cả comment redis.lrange(referer, 0, -1)

  3. Xóa comment redis.lrem(referer, 0, comment). Xóa tất cả occurrence của comment trong list key referer.

API ready. Tích hợp frontend với backend.

Thiết Lập Client Side

Không khó. Chỉ cần hit endpoints vừa tạo dùng fetch. Dùng library swr cho caching và revalidation comments. Tự do dùng React Query hoặc thư viện khác.

Tạo hook useComment() có handler onSubmit() và onDelete() làm request.

"use client";
import { useState } from "react";
import type { Comment } from "@/app/interfaces/interfaces";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
const useComment = () => {
  const [text, setText] = useState("");
  const { data: comments, mutate } = useSWR<Comment[]>(
    "/api/comment/get",
    fetcher,
    { fallbackData: [], },
  );
  const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    try {
      await fetch("/api/comment/post", {
        method: "POST",
        body: JSON.stringify({ text }),
        headers: { "Content-Type": "application/json", },
      });
      setText("");
      await mutate();
    } catch (error) {
      console.log(error);
    }
  };
  const onDelete = async (comment: Comment) => {
    try {
      await fetch("/api/comment/delete", {
        method: "POST",
        body: JSON.stringify({ comment }),
        headers: { "Content-Type": "application/json", },
      });
      await mutate();
    } catch (error) {
      console.log(error);
    }
  };
  return { text, setText, comments, onSubmit, onDelete };
};
export default useComment;

Comment section xong. Fetch, post, delete comments được. Bước tiếp tạo component Comment box và comments list. Complete sample tại đây.