reCAPTCHA와 Next.js 통합

이 게시물에서는 reCAPTCHA를 Next.js 애플리케이션에 통합하는 방법을 시연합니다.

그러나 시작하기 전에 먼저 reCAPTCHA의 작동 방식을 파악해 보겠습니다. 문의 양식이 있는 포트폴리오 웹 사이트를 구축했지만 실제 메시지를 받는 대신 많은 스팸을 받았다고 가정합니다. 이러한 스팸 메시지는 봇에 의해 생성되었습니다. 봇을 차단하기 위해 reCAPTCHA를 활용합니다.

지금 바로 실행해 보겠습니다. 먼저 이 웹사이트로 이동하여 관련 정보로 양식을 작성합니다(아래 참조).


양식을 제출하면 사이트 키(브라우저에서 볼 수 있음)와 비밀 키가 제공됩니다. 아래와 같이 .env.local에 추가하십시오.


이제 reCAPTCHA를 Next.js 12와 통합하기 시작합니다.



프로젝트 레포(개인 포트폴리오 사이트입니다):- https://github.com/Sumukha210/new-portfolio-website



다른 종속성과 함께 Next.js 설치,



npx create-next-app@latest --typescript

또는



yarn create next-app --typescript 

그런 다음 이 패키지를 추가하고

yarn add  react-google-recaptcha-v3


이 코드를 _app.tsx(또는 .jsx) 파일에 추가하세요. 여기서 우리는 구성 요소를 GoogleRecaptchaProvider로 래핑합니다.

import type { AppProps } from "next/app";
import "@/styles/styles.scss";
import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <GoogleReCaptchaProvider
      reCaptchaKey={process.env.NEXT_PUBLIC_RECAPTHA_SITE_KEY}
      scriptProps={{
        async: false, // optional, default to false,
        defer: true, // optional, default to false
        appendTo: "body", // optional, default to "head", can be "head" or "body",
        nonce: undefined,
      }}>
      <Component {...pageProps} />;
    </GoogleReCaptchaProvider>
  );
}

export default MyApp;


이제 양식을 배치한 페이지에 이 코드를 추가하십시오. 여기서는 먼저 useGoogleRecaptcha hook을 가져오고 양식이 확인되면 reCAPTCHA가 로드되었는지 여부를 확인하고 있으면 함수에서 반환합니다. 오류가 없으면 다른 데이터와 함께 토큰을 서버로 보냅니다.

import React, { useState } from "react";
import { useGoogleReCaptcha } from "react-google-recaptcha-v3";
import { Wrapper, SubmitBtn } from "./RightSectionStyles";
import axios from "axios";
import { responseTypes } from "@/utils/types";

const RightSection = () => {
  const [isBtnDisabled, setBtnDisabled] = useState(false);
  const { executeRecaptcha } = useGoogleReCaptcha();
  const [response, setResponse] = useState<responseTypes | null>(null);

  const handleSubmit = async (e: any) => {
    e.preventDefault();
    const name = e.target[0];
    const email = e.target[1];
    const message = e.target[2];

    [name, email, message].forEach(item => {
      if (item.validity.valid === false && item.validity.valid) {
        return;
      }
    });

    setBtnDisabled(true);

    if (!executeRecaptcha) {
      return;
    }

    try {
      const token = await executeRecaptcha();
      if (!token) {
        setResponse({ message: "Failed to Send!!!", status: "Failed" });
        return;
      }

      const result = await axios.post("/api/contactUs", {
        token,
        name: name.value,
        email: email.value,
        message: message.value,
      });
      console.log(result);

      if (result.data) {
        setResponse({
          message: result.data.message,
          status: result.data.status,
        });
      }
      setBtnDisabled(false);
    } catch (error) {
      console.log(error);
      setResponse({ message: "Failed to Send!!!", status: "Failed" });
      setBtnDisabled(false);
    }
  };

  return (
    <Wrapper>
      <form onSubmit={handleSubmit}>
        <div className="flex">
          <section>
            <input
              type="text"
              placeholder="Enter your name"
              name="name"
              required
            />
          </section>

          <section>
            <input
              type="email"
              placeholder="Enter your email"
              name="email"
              required
            />
          </section>
        </div>

        <section>
          <textarea
            name="message"
            placeholder="Enter your message"
            cols={30}
            rows={10}></textarea>
        </section>

        <div className="responseText">
          <h3
            className="subtitle-4"
            style={{
              color: response?.status === "Failed" ? "red" : "#24ff72",
            }}>
            {response?.message}
          </h3>
        </div>

        <div className="btnContainer">
          <SubmitBtn disabled={isBtnDisabled} type="submit" marginTop="2rem">
            <span>Submit{isBtnDisabled && "ting"}</span>
            {isBtnDisabled && <span className="loader"></span>}
          </SubmitBtn>
        </div>
      </form>
    </Wrapper>
  );
};

export default RightSection;


/pages/api에서 새 파일(엔드포인트) contactUs.ts를 생성하고 이 코드를 추가합니다.

import { responseTypes } from "@/utils/types";
import axios from "axios";
import type { NextApiRequest, NextApiResponse } from "next";

const verifyRecaptcha = async token => {
  const secretKey = process.env.RECAPTHA_SECRET_KEY;

  var verificationUrl =
    "https://www.google.com/recaptcha/api/siteverify?secret=" +
    secretKey +
    "&response=" +
    token;

  return await axios.post(verificationUrl);
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<responseTypes>
) {
  try {
    const name = req.body.name;
    const email = req.body.email;
    const message = req.body.message;
    const token = req.body.token;

    // Recaptcha response
    const response = await verifyRecaptcha(token);

    // Checking if the reponse sent by reCaptcha success or not and if the score is above 0.5
    // In ReCaptcha v3, a score sent which tells if the data sent from front end is from Human or from Bots. If score above 0.5 then it is human otherwise it is bot
    // For more info check, https://developers.google.com/recaptcha/docs/v3
    // ReCaptcha v3 response, {
    //     "success": true|false,      // whether this request was a valid reCAPTCHA token for your site
    //     "score": number             // the score for this request (0.0 - 1.0)
    //     "action": string            // the action name for this request (important to verify)
    //     "challenge_ts": timestamp,  // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
    //     "hostname": string,         // the hostname of the site where the reCAPTCHA was solved
    //     "error-codes": [...]        // optional
    //   }
    if (response.data.success && response.data.score >= 0.5) {
      return res
        .status(200)
        .json({ status: "Success", message: "Thank you for contacting me." });
    } else {
      return res.json({
        status: "Failed",
        message: "Something went wrong, please try again!!!",
      });
    }
  } catch (error) {
    console.log("ERRRRROr", error);
    res.json({
      status: "Failed",
      message: "Something went wrong, please try again!!!",
    });
  }
}

좋은 웹페이지 즐겨찾기