Computer >> 컴퓨터 >  >> 프로그래밍 >> Redis

Redis 및 NextAuth를 사용하여 Next.js 블로그를 위한 보안 댓글 시스템 만들기

이 튜토리얼️에서는 블로그에 대한 댓글 섹션을 구축할 것입니다. 우리가 될 기술 스택은 다음과 같습니다:

  1. NextJS 13(앱 디렉토리)
  2. NextAuth(인증용)
  3. Upstash Redis(댓글 저장용)
  4. SWR(댓글 캐싱 및 재검증용)

시작해 보겠습니다.

NextAuth로 인증 처리

첫째, 누구나 댓글을 게시하도록 할 수는 없습니다. 그렇죠? 누군가가 스크립트를 실행하여 귀하의 블로그에 댓글을 스팸으로 보낼 수도 있습니다. 사람들이 댓글을 게시할 수 있도록 하기 전에 먼저 인증 시스템을 구축해 보겠습니다. NextAuth를 사용하겠습니다.

next-auth 설치 프로젝트에 참여하세요.

pnpm install next-auth

이는 앱 디렉토리 내부의 디렉토리 구조입니다

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

인증 API 경로를 설정하세요:

// 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 };

여기에서 새 Github OAuth 애플리케이션을 생성하여 GITHUB_CLIENT_ID를 가져옵니다. 그리고 GITHUB_CLIENT_SECRET .

Redis 및 NextAuth를 사용하여 Next.js 블로그를 위한 보안 댓글 시스템 만들기

이제 NextAuth를 사용하면 signIn를 사용하여 모든 클라이언트 구성 요소에서 로그인 및 로그아웃할 수 있습니다. 및 signOut next-auth의 함수 . 하지만 그 전에 전체 애플리케이션을 래핑하는 컨텍스트 제공자를 설정해야 합니다.

// 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 이를 통해 애플리케이션의 모든 클라이언트 구성 요소에서 세션 상태에 액세스할 수 있습니다.

useSession를 사용하여 세션 상태에 액세스할 수 있습니다. next-auth의 후크 . 다음은 로그인 버튼의 샘플입니다:

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

이를 통해 인증 시스템이 마련되었습니다. 이제 Redis 데이터베이스에 주석을 저장하기 위한 서버 측 경로를 시작하겠습니다.

Redis 데이터베이스 설정

  1. Upstash로 이동하여 Redis 데이터베이스를 생성하세요.
  2. 사용자와 가까운 지역을 선택하고 TLS 암호화를 선택하세요.
  3. @upstash/redis 설치 패키지.
pnpm install @upstash/redis

Redis 및 NextAuth를 사용하여 Next.js 블로그를 위한 보안 댓글 시스템 만들기

  1. 이 토큰을 .env.local에 복사하세요. .

이제 이 디렉토리 구조에 API 엔드포인트를 작성해 보겠습니다.

.
├── app
│ ├── api
│ │ ├── auth
│ │ │ └── [...nextauth]
│ │ │ └── route.ts
│ │ ├── comment
│ │ │ ├── delete
│ │ │ │ └── route.ts
│ │ │ ├── get
│ │ │ │ └── route.ts
│ │ │ └── post
│ │ │ └── route.ts
│ │ └── lib
│ │ ├── getUser.ts
│ │ └── redis.ts
  1. Redis 클라이언트 인스턴스 생성
// app/api/lib/redis.ts
import { Redis } from "@upstash/redis";
 
/*
This tries to load UPSTASH_REDIS_REST_URL
and UPSTASH_REDIS_REST_TOKEN from your environment
using process.env
*/
const redis = Redis.fromEnv();
 
export default redis;

그게 다야. 이제 Redis 클라이언트가 설정되었으며 남은 것은 애플리케이션에서 이에 대한 API 경로를 설정하는 것뿐입니다.

우리는 설명을 저장하기 위해 Redis 목록을 사용할 것입니다. 스택 역할을 할 수 있으므로 가장 최근 댓글이 맨 위에 표시됩니다. 물론 클라이언트측에서 정렬 논리를 구현할 수도 있지만 Redis가 이미 이 데이터 구조를 제공하고 있다면 이를 사용해 보겠습니다.

여기에서 전체 코드를 볼 수 있습니다. 요점은 다음과 같습니다:

  1. 댓글 작성:redis.lpush(referer, comment) . 그러면 referer 키가 있는 목록에 주석이 푸시됩니다.

  2. 모든 댓글 가져오기 redis.lrange(referer, 0, -1)

  3. redis.lrem(referer, 0, comment) 댓글 삭제 . comment가 모두 삭제됩니다. referer 키가 있는 목록에서 .

이제 API가 준비되었습니다. 프런트엔드와 백엔드를 통합해 보겠습니다.

클라이언트 측 설정

그다지 어렵지 않습니다. fetch를 사용하여 방금 생성한 엔드포인트에 접속하면 됩니다. .우리는 swr라는 라이브러리를 사용할 것입니다. 댓글 캐싱 및 재검증을 위해. 하지만 React Query와 같은 다른 라이브러리를 사용해도 됩니다.

우리는 useComment()을 만듭니다 onSubmit()을 갖는 후크 및 onDelete() 요청을 처리하는 핸들러입니다.

"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;

이제 댓글 섹션이 완료되었습니다. 댓글을 가져오고, 게시하고, 삭제할 수 있습니다. 다음 단계는 설명 상자 및 설명 목록에 대한 구성 요소를 만드는 것입니다. 다음은 전체 샘플입니다