尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Next.js 集成 Cloudflare Turnstile 实战:隐式/显式渲染与 API 路由服务端校验详解

Next.js 集成 Cloudflare Turnstile 实战:隐式/显式渲染与 API 路由服务端校验详解 Next.js 集成 Cloudflare Turnstile 实战隐式/显式渲染与 API 路由服务端校验详解【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js本文基于 Next.js 仓库中的官方示例 examples/cloudflare-turnstile 展开完整讲解如何在一个 Next.js 项目中接入 Cloudflare Turnstile 智能人机验证从 Cloudflare 后台获取密钥、配置环境变量到隐式自动渲染与显式API渲染两种前端集成方式再到通过 Next.js API 路由完成服务端的 token 校验。读完后你能够在自己的 Next.js 项目中落地一套无感验证 服务端校验的完整人机防护方案。什么是 Cloudflare TurnstileTurnstile 是 Cloudflare 提供的智能 CAPTCHA 替代方案。与普通验证码图形点选、滑块拖动等不同它具备两个核心特性无需经过 Cloudflare 流量中转可以嵌入任何网站不要求站点本身的流量走 Cloudflare 网络可无感工作在风控判断访客可信时可以不向访客展示任何验证码界面从而减少对正常用户的干扰。其工作原理是两段式的客户端页面加载 Turnstile 官方脚本渲染一个验证组件。访客交互或直接通过后组件生成一个验证 token并以cf-turnstile-response字段随表单提交服务端后端拿到 token 后调用 Cloudflare 的siteverify接口携带站点 Secret Key 换取验证结果以此决定是否放行请求。示例项目正是用两个页面分别演示了这两种渲染方式再用一个 API 路由演示了服务端校验代码量非常精简适合直接作为接入模板。项目结构与获取方式示例位于仓库的examples/cloudflare-turnstile/目录整体结构如下pages/implicit.tsx隐式渲染自动渲染演示页也是默认首页pages/explicit.tsx显式渲染手动调用turnstile.render演示页pages/api/handler.ts服务端校验用的 API 路由pages/_app.tsx全局应用入口next.config.js路由改写配置app.css演示页的居中布局样式.env.local.example环境变量模板。从 package.json 可以看到该示例基于 Next.jsnext: latest React 18 TypeScript构建与运行脚本均为标准的next dev/next build/next start。按 README 的说明使用create-next-app引导创建该示例的命令如下npm / Yarn / pnpm 三选一npx create-next-app --example cloudflare-turnstile cloudflare-turnstile-appyarn create next-app --example cloudflare-turnstile cloudflare-turnstile-apppnpm create next-app --example cloudflare-turnstile cloudflare-turnstile-app创建完成后即可npm run dev启动本地开发服务器启动前需先完成下文的环境变量配置。配置 Cloudflare Turnstile获取 Site Key 与 Secret Key按 README 给出的操作步骤登录 Cloudflare 控制台选择你的账号进入 Turnstile 管理页点击Add a site填写表单通常包含站点域名与验证码模式创建完成后复制你的Site Key和Secret Key备查。两者分工明确密钥用途可见性Site Key前端渲染验证组件时标识这是哪个站点会下发到浏览器属于公开信息Secret Key服务端调用 siteverify 校验 token 时证明这是合法的站点后端绝不可暴露到浏览器只能存在于 Node.js 环境配置环境变量将示例目录下的.env.local.example复制为.env.localcp .env.local.example .env.local然后打开.env.local填入两个环境变量NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEYCLOUDFLARE_TURNSTILE_SECRET_KEY.env.local.example 中对两者的注释写得很清楚# Public Environment variables that can be used in the browser. NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY # Secret environment variables only available to Node.js CLOUDFLARE_TURNSTILE_SECRET_KEY这正体现了 Next.js 环境变量的作用域规则以NEXT_PUBLIC_前缀开头的变量会被内联进客户端 bundle可以在浏览器端读取示例中用于渲染组件不带该前缀的变量只在 Node.js 侧服务端渲染与 API 路由可用不会泄露给浏览器示例中用于服务端校验。部署到云环境时需在部署平台的Environment Variables中配置与.env.local一致的两项尤其是 Secret Key 不能只放在本地文件里。隐式渲染一行 div 自动出组件隐式渲染implicit rendering是最简单的接入方式只需加载 Turnstile 官方脚本并在页面中放置一个带特定 class 和data-sitekey属性的空div脚本加载完成后会自动将其替换为验证组件。pages/implicit.tsx 的完整实现import Script from next/script; export default function ImplicitRender() { return ( main Script srchttps://challenges.cloudflare.com/turnstile/v0/api.js async{true} defer{true} / form methodPOST action/api/handler h2Dummy Login Demo/h2 div classNamecf-turnstile checkbox >import Script from next/script; type RenderParameters { sitekey: string; theme?: light | dark; callback?(token: string): void; }; declare global { interface Window { onloadTurnstileCallback(): void; turnstile: { render(container: string | HTMLElement, params: RenderParameters): void; }; } } export default function ExplicitRender() { return ( main Script idcf-turnstile-callback {window.onloadTurnstileCallback function () { window.turnstile.render(#my-widget, { sitekey: ${process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY}, }) }} /Script Script srchttps://challenges.cloudflare.com/turnstile/v0/api.js?onloadonloadTurnstileCallback async{true} defer{true} / form methodPOST action/api/handler h2Dummy Login Demo/h2 div idmy-widget classNamecheckbox / button typesubmitSign in/button p Go to the a href/implicitimplicit render demo/a /p /form /main ); }用onload查询参数挂接加载回调脚本 URL 写作api.js?onloadonloadTurnstileCallback即 Turnstile SDK 加载完成后会自动调用名为onloadTurnstileCallback的全局函数。这里刻意不用window.addEventListener(load, ...)而是利用官方 SDK 的onload参数确保回调一定在 SDK 就绪之后触发规避脚本加载时序问题在回调里调用window.turnstile.render第一个参数是容器选择器字符串或 DOM 元素第二个参数是渲染参数。示例中定义了RenderParameters类型从源码结构看其可接受的核心参数包括sitekey: string必填站点 Site Keytheme?: light | dark组件主题可控制明暗风格callback?(token: string)验证成功后的回调参数即为生成的 token可用于在 JS 层面直接拿到 token 做异步提交而不必依赖表单隐藏字段容器是普通空 divdiv idmy-widget /不需要cf-turnstileclass是否渲染完全由render调用决定。文件顶部的declare global为window.turnstile补充了 TypeScript 声明使render调用具备类型提示这是显式渲染模式下保持类型体验的小技巧。两种方式对比隐式渲染适合标准登录/注册表单这类快速接入场景显式渲染适合需要在组件生命周期内执行自定义逻辑例如拿到 token 后立即发起 fetch、根据theme跟随深色模式切换、在表单提交前手动turnstile.reset()等的场景。服务端校验API 路由与 siteverify 接口客户端拿到的 token 只应被视为待验证凭证真正的裁决在服务端完成。示例的服务端逻辑全部在 pages/api/handler.ts 中完整代码如下import type { NextApiRequest, NextApiResponse } from next; export default async function Handler( req: NextApiRequest, res: NextApiResponse, ) { const form new URLSearchParams(); form.append(secret, process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY); form.append(response, req.body[cf-turnstile-response]); form.append(remoteip, req.headers[x-forwarded-for] as string); const result await fetch( https://challenges.cloudflare.com/turnstile/v0/siteverify, { method: POST, body: form }, ); const json await result.json(); res.status(result.status).json(json); }逐行拆解这段实现secret取自process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY。由于该变量没有NEXT_PUBLIC_前缀只在 Node.js 侧可读天然不会进入客户端 bundle满足Secret Key 不出服务端的安全要求response即客户端表单提交的cf-turnstile-response也就是要验证的 tokenremoteip从x-forwarded-for请求头取出访客 IP。在反向代理或云托管环境如示例所面向的 Vercel 部署中应用直接拿到的连接地址通常是代理层地址需要借助x-forwarded-for才能获得真实访客 IP供 Cloudflare 风控参考siteverify端点https://challenges.cloudflare.com/turnstile/v0/siteverify是 Cloudflare 官方的验证入口采用application/x-www-form-urlencoded形式 POSTURLSearchParams序列化恰好就是该格式。最后res.status(result.status).json(json)把 Cloudflare 的响应原样透传给前端前端可据此判断success等字段决定后续业务逻辑示例中即Dummy Login演示实际项目应在此处接上自己的登录/注册流程。这里需要注意两个工程细节token 校验必须在服务端做前端提交的任何值都不可信只有携带 Secret Key 调用 siteverify 得到的结果才能作为裁决依据API 路由需保证req.body可用Next.js 的 API 路由默认会对 JSON 请求体做解析本示例表单是默认的浏览器表单提交application/x-www-form-urlencoded字段cf-turnstile-response会被解析进req.body。如果改为前端 fetch 提交 JSON则应使用Content-Type: application/json取值字段名保持一致即可。路由组织把隐式渲染设为首页next.config.js 只做了路由改写module.exports { async rewrites() { return [ { source: /, destination: /implicit, }, ]; }, };通过rewrites()将根路径/指向/implicit页面使访客打开站点首页时默认看到隐式渲染演示两个演示页之间又通过页内链接/implicit↔/explicit互相跳转形成完整的对照体验。pages/_app.tsx 则是标准的全局入口负责引入app.css并渲染路由组件与 Turnstile 逻辑解耦。小结与适用说明这套示例完整覆盖了接入 Cloudflare Turnstile 的三个关键环节配置Cloudflare 后台创建站点获取 Site Key / Secret Key通过.env.local分别以NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY客户端可见和CLOUDFLARE_TURNSTILE_SECRET_KEY仅 Node.js 侧可见注入前缀即作用域前端渲染隐式渲染靠cf-turnstileclass 与data-sitekey自动完成显式渲染通过api.js?onload...回调中调用window.turnstile.render可传sitekey、theme、callback等参数做精细控制服务端校验API 路由将secret、responsetoken、remoteip以表单编码 POST 到siteverify端点以响应结果为准放行请求。适用前提与限制示例基于 Next.js Pages Router 与 React 18API 校验用的是 API 路由pages/api若你的项目使用 App Router可将同样的fetch校验逻辑迁移到 Route Handler 中实现核心参数与端点不变。部署时务必在托管平台的 Environment Variables 中配置这两项变量尤其 Secret Key仅依赖仓库中的.env.local只适用于本地开发。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表