Next.js中如何设置仅完成reCaptcha验证后才可跳转访问表单页面
Next.js 验证码页跳转访问限制方案
实现思路
核心逻辑是在验证码验证通过后生成可校验的凭证,表单页/全局路由层校验凭证存在才允许访问,同时后端对表单提交的凭证做二次校验避免前端校验被绕过。
具体实现步骤
- 第一步:修改验证码页逻辑,存储验证凭证
你原有代码直接在验证码回调跳转,现在需要拿到谷歌返回的验证token,存储到本地后再跳转:
function Captcha() { const reRef = useRef<ReCAPTCHA>(null); const router = useRouter() // 验证码通过回调会拿到返回的token const handleVerifySuccess = (token: string) => { // 存到sessionStorage,关闭浏览器自动失效,也可以换成存cookie方便中间件读取 sessionStorage.setItem('captcha_pass_token', token); router.push('/form'); } return ( <div className={styles.container}> <h1>Подтвердите, что вы не робот</h1> <ReCAPTCHA sitekey={`${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`} size="normal" ref={reRef} onChange={handleVerifySuccess} /> </div> ); }
- 第二步:表单页加访问拦截
如果你用Pages Router
直接在表单页组件内加校验逻辑,无凭证直接跳回验证码页:
import { useRouter } from 'next/router' import { useEffect } from 'react' export default function FormPage() { const router = useRouter(); useEffect(() => { const passToken = sessionStorage.getItem('captcha_pass_token'); if (!passToken) { router.replace('/'); } }, [router]) // 原有表单逻辑... }
如果你用App Router
可以用中间件全局拦截/form路由,更统一,不需要每个页面加校验:
- 先把之前存储凭证的逻辑换成存cookie,方便中间件读取:
// 验证码页的handleVerifySuccess方法修改 const handleVerifySuccess = (token: string) => { // cookie有效期设1小时,path设为全站可访问 document.cookie = `captcha_pass_token=${token}; path=/; max-age=3600; SameSite=Lax`; router.push('/form'); }
- 根目录新建
middleware.ts文件,添加路由拦截逻辑:
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { if (request.nextUrl.pathname === '/form') { const passToken = request.cookies.get('captcha_pass_token')?.value; if (!passToken) { // 无凭证跳回验证码页 return NextResponse.redirect(new URL('/', request.url)); } } return NextResponse.next(); } export const config = { matcher: '/form', }
- 第三步:后端二次校验(必须做)
前端所有校验逻辑都可以通过浏览器调试绕过,所以你在表单提交的时候,必须把存储的captcha_pass_token一起传到后端,调用谷歌reCAPTCHA服务端验证接口校验token的有效性,校验不通过直接拒绝表单提交,这样就算有人绕过前端拦截进入表单页,也无法提交数据,彻底满足安全要求。
内容的提问来源于stack exchange,提问作者George Rykunov
相关产品推荐
相关产品推荐

