1

I have a Next.js app, index page contains only captcha, and after successfull entry redirects to form at mydomain.com/form and that works just fine. But also i can just enter in browser

mydomain.com/form

and get to it without captcha, which i obviously dont want.

Is there a way to restrict all entries except redirect from captcha page? Found only solutions with logins, e.t.c which i dont need.

Im using react-google-recaptcha package

Here is my index page

function Captcha() {
  const reRef = useRef<ReCAPTCHA>(null);
  const router = useRouter()
  return (
    <div className={styles.container}>
      <h1>Подтвердите, что вы не робот</h1>
      <ReCAPTCHA
        sitekey={`${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`}
        size="normal"
        ref={reRef}
        onChange={() => router.push('/form')}
      />
    </div>
  );
}
juliomalves
  • 42,130
  • 20
  • 150
  • 146

2 Answers2

0

The logic is same with that of authorizing restricted page based on authentication context.

In this case, create a Context Provider that contains the state whether reCaptcha validation has been done. Then use useContext in your form component to either render or redirect based on the state provided by the reCaptcha context

RobLjm
  • 399
  • 2
  • 11
0

Solved it using this guide.

TL:DR Basically im adding a token to local storage after successful captcha, token is necessary to access form page.

Created a HOC named withAuth

import { useRouter } from "next/router";
const withAuth = (WrappedComponent: any) => {
  return (props: JSX.IntrinsicAttributes) => {
    // checks whether we are on client / browser or server.
    if (typeof window !== "undefined") {
      const Router = useRouter();

      const accessToken = localStorage.getItem("accessToken");

      // If there is no access token we redirect to "/" page.
      if (!accessToken) {
        Router.replace("/");
        return null;
      }

      // If this is an accessToken we just render the component that was passed with all its props

      return <WrappedComponent {...props} />;
    }

    // If we are on server, return null
    return null;
  };
};



export default withAuth;

Changed captcha page to clean local storage on every load and put a token in after successful entry.

    function Captcha() {
  const reRef = useRef<ReCAPTCHA>(null);
  const router = useRouter()
  if(process.browser){localStorage.clear()}
  
  return (
    <div className={styles.container}>
      <h1>Подтвердите, что вы не робот</h1>
      <ReCAPTCHA
        sitekey={`${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`}
        size="normal"
        ref={reRef}
        onChange={() => 
          {
            localStorage.setItem("accessToken" , "1"),
            router.push('/form')
          }
        }
      />
    </div>
  );
}

export default Captcha;

And passed my form component to withAuth (changed from export default Home)

export default withAuth(Home);
  • Answers that are little more than only a link are not encouraged in SO. Consider adding the solution in your answer and keeping the link only for reference. – nullptr Sep 23 '21 at 06:44