如何用React和Django实现reCAPTCHA的客户端-服务器端

364 阅读8分钟

用React和Django实现reCAPTCHA的客户端-服务器端

谷歌提供了一项被称为reCAPTCHA的服务,它有助于阻止恶意用户进入你的网站。它通过提出一个对人类来说简单而对机器人来说困难的挑战来做到这一点。

本教程将告诉你如何在你的Django和React应用程序中实现Google reCAPTCHA v2。

前提条件

为了能够跟上本文的进度,读者应该具备以下条件

  • 安装了Node.js。
  • 安装了Python。
  • 基本的React知识。
  • 基本的Python和Django知识。
  • 对Django Rest框架的基本了解。
  • 了解Fetch API。

目标

在本文结束时,读者将能够。

  • 在一个网站中实施reCAPTCHA。
  • 在服务器端验证 reCAPTCHA 响应,并采取适当的行动。
  • 连接React前端和Django后端。

获取我们的网站和秘钥

要在你的网站上启用reCAPTCHA,你首先需要在reCAPTCHA网站上注册你的网站,这样你就能获得网站和密匙。

填写所需信息,如下所示。

  • 标签文本字段中,输入你的网站名称。
  • reCAPTCHA部分,选择reCAPTCHA v2。 在出现的选项列表中,选择选项1("我不是一个机器人 "复选框)。
  • 域名部分,输入以下两个选项。127.0.0.1 和 localhost。
  • 接受reCAPTCHA的服务条款并点击提交。
  • 然后你将得到一个网站密钥(在前端使用)和一个秘密密钥(在后端)。

Recaptcha

设置我们的前端

创建一个名为react-django-recaptcha的文件夹。

在你的终端中打开该文件夹并运行以下命令。

npx create-react-app frontend

上面的命令将创建我们的React前台。

接下来,运行下面的命令,导航到前端目录。

cd frontend
npm i react-google-recaptcha

上面的命令将Google reCAPTCHA v2软件包安装到我们的项目中。我们将用它来在前端设置reCAPTCHA。

现在,打开App.js 文件,用以下代码修改其中的代码。

import './App.css';
import { useState } from 'react';
import ReCAPTCHA from "react-google-recaptcha";

function App() {

  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [message, setMessage] = useState('')
  const [captchaResult, setCaptchaResult] = useState()

  const handleSubmit = (e) => {
    e.preventDefault()

    // Handle form submission here

  }

     const handleRecaptcha = (value) => {

       fetch('http://127.0.0.1:8000/recaptcha/', {
         method: 'POST',
         body: JSON.stringify({ 'captcha_value': value }),
         headers: { 'Content-Type': 'application/json' }
       })
        .then(res => res.json())
        .then(data => {
          console.log(data.captcha.success)
          setCaptchaResult(data.captcha.success)
        }) 
     }

  return (
    <div className="container">
      <h2>Contact us:</h2>
      <form>
        <label>Name</label>
        <input type="text" name="name" placeholder="Your name.." value={name} onChange={(e) => {setName(e.target.value)}} />

        <label>Email</label>
        <input type="email" name="email" placeholder="example@domain.com" value={email} onChange={(e) => {setEmail(e.target.value)}} />

        <label>Subject</label>
        <textarea name="subject" placeholder="Write something.." value={message} onChange={(e) => {setMessage(e.target.value)}} />

        <div className="cta">
          <ReCAPTCHA
            sitekey="YOUR SITE KEY"
            onChange={handleRecaptcha}
          />
          
          {
             captchaResult && <button type='submit' onClick={(e) => {handleSubmit(e)}}>Submit</button>
          }
        </div>
  </form>
</div>
  );
}

export default App;
  • 在上面的代码中,我们有一个联系表单,其中包含的字段有:姓名、电子邮件和信息。我们使用useState() 钩子跟踪这些字段中输入的数据。
  • div 与classNamecta ,我们有我们的ReCaptcha组件,需要两个属性。一个是我们从Google reCAPTCHA网站获得的网站密钥。另一个属性是onChange ,当reCAPTCHA组件被点击时调用handleRecaptcha() 函数。
  • 在reCAPTCHA组件下面,我们根据reCAPTCHA的结果有条件地呈现Submit 按钮。我们只在reCAPTCHA的成功值评估为真时(当用户成功解决了reCAPTCHA的挑战时)显示它。这有助于确保只有在解决了reCAPTCHA挑战后才能提交表单数据。
  • handleRecaptcha() 函数接收一个值,我们将其发送到后台进行服务器端验证。你可以通过 console.log 来查看这个值。接下来,我们使用Fetch API向路由http://127.0.0.1:8000/recaptcha/ 发出POST请求,稍后我们将在服务器上创建这个路由。然后我们使用从服务器得到的响应,并将其传递给setCaptchaResult() 函数,该函数设置了captchaResult 的状态。响应要么是真,要么是假。如果是真的,我们就显示Submit 按钮。
  • 在显示提交按钮后(这意味着reCAPTCHA挑战已经成功解决),你可以继续使用handleSubmit() 函数处理表单提交。

现在,打开App.css ,用下面的代码进行修改,使我们的网页看起来更好。

body {
    background: #f2f2f2;
    height: 100vh;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.container {
    max-width: 80%;
    border-radius: 5px;
    background-color: white;
    padding: 20px;
}
input[type="text"],
[type="email"],
textarea {
    width: 100%;
    padding: 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
    margin-top: 6px;
    margin-bottom: 16px;
    resize: vertical;
}

.cta {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

button {
    background-color: #04aa6d;
    color: white;
    padding: 12px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    margin-top: 1rem;
}

运行我们的前端。打开集成终端,输入以下命令。

npm start

这将在本地开发服务器中打开我们的项目。在你的网络浏览器上打开127.0.0.1:3000 ,查看网页。

设置我们的后端

为了设置我们的后端,我们首先需要创建一个虚拟环境。

打开命令提示符,cd 进入我们的react-django-recaptcha 文件夹。

键入以下命令来创建一个虚拟环境。

python -m venv recaptcha-env

这将创建一个虚拟环境,名称为recaptcha-env

要激活这个虚拟环境,请键入以下命令。

.\recaptcha-env\Scripts\activate

现在我们已经激活了我们的虚拟环境,让我们继续并通过运行以下命令来安装Django。

python -m pip install Django

接下来,在同一目录下执行以下命令。

django-admin startproject recaptchaVerification

cd recaptchaVerification

code .

第一条命令创建一个名称为recaptchaVerification 的Django应用程序,第二条命令改变我们的活动目录,最后一条命令启动我们的代码编辑器。

打开集成终端,确保虚拟环境仍处于活动状态。如果不是,输入以下命令来激活它。

cd ..
.\recaptcha-env\Scripts\activate

为了确保我们的服务器正常工作,运行以下命令(记得在运行该命令之前,cd 进入recaptchaVerification 目录)。

python manage.py runserver

现在,让我们创建一个新的应用程序来处理我们的API请求。

运行下面的命令,创建一个名为api 的应用程序。

django-admin startapp api

接下来,继续安装所有的依赖项,如下所示。

pip install djangorestframework

python -m pip install requests

python -m pip install django-cors-headers

第一条命令是安装Django Rest Framework,它可以帮助我们创建一个API。

  • 第二条命令安装Requests HTTP库,帮助我们轻松地发送HTTP请求。我们将用它来向Google ReCAPTCHA发送HTTP请求,以验证用户的响应。
  • 最后一条命令安装 CORS,允许从其他来源向你的 Django 应用程序发出浏览器内请求。这将使我们的React前端能够向我们的Django后端发出请求。

修改settings.py 文件。打开settings.py 文件,修改INSTALLED_APPSMIDDLEWARE 部分,如下图所示。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'api.apps.ApiConfig', #registers our api app

    'rest_framework',

    'requests',

    'corsheaders'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',

     "corsheaders.middleware.CorsMiddleware",

    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',  
]

settings.py 文件的底部,添加以下几行代码。

CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000",
]

你会注意到,我们已经添加了跨源资源共享(CORS)。CORS是一种机制,它允许网页上的受限资源从第一个资源所来自的域之外的另一个域被请求。因此,上述阵列确保我们的两个应用程序可以进行通信。

修改recaptchaVerification\urls.py 文件。打开位于recaptchaVerification 目录中的urls.py 文件,并按如下所示进行修改。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('api.urls'))
]

这将有助于将所有的请求路由到我们的api应用程序。

在api应用程序上工作。在我们先前创建的api 文件中,打开views.py 文件并按如下所示进行修改。

import requests
from rest_framework.response import Response
from rest_framework.decorators import api_view

@api_view(['POST'])
def recaptcha(request):
    r = requests.post(
      'https://www.google.com/recaptcha/api/siteverify',
      data={
        'secret': 'YOUR SECRET KEY',
        'response': request.data['captcha_value'],
      }
    )

    return Response({'captcha': r.json()})
  • 在上面的代码中,我们使用了Django Rest框架提供的@api_view 装饰器,以限制只有POST请求到这个API路由。
  • 然后我们使用request HTTP库向https://www.google.com/recaptcha/api/siteverify 发出POST请求。这个API post请求可以带三个参数;secretresponse ,和remoteip
  • secret 是Google reCAPTCHA网站提供的密匙,response 是当用户解决了验证码挑战时我们从前端得到的用户响应令牌,remoteip 是用户的IP地址。前两个是必须的,但remoteip 是可选的。因此,在我们的例子中,我们只使用了secretresponse
  • API响应的JSON对象包含以下属性:success ,是真还是假;challenge_ts ,是挑战的时间戳;hostname ,是我们解决验证码的网站的主机名(在我们的例子中是localhost);error-codes ,是可选的。
  • 我们将API响应存储在r ,然后将其作为JSON对象发送到前端。

在同一个API文件夹中,创建一个urls.py 文件,并按如下所示进行修改。

from django.urls import path
from . import views

urlpatterns = [
    path('recaptcha/', views.recaptcha)
]

上面的代码暴露了我们的API端点,前端将访问该端点。

测试我们的应用程序

为了测试我们的应用程序,确保React前端和Django后端正在运行。现在去你的浏览器localhost:3000 。你会注意到,我们的联系表单没有提交按钮。

接下来,解决reCAPTURE挑战,注意到提交按钮出现了,只有这样你才能提交表单。这确保了在提交数据之前,有人必须解决验证码挑战。

你还会注意到,验证码验证会显示一条信息,verification expired ,过了一会儿。重新勾选复选框,提交按钮就会消失。这意味着我们的应用程序是有效的,因为只有当服务器响应success = true ,才会显示提交按钮。

总结

在React应用程序中实施Google reCAPTCHA是很容易的,它可以给你的应用程序提供另一层安全保护,以防止机器人。它提供了一个伟大而简单的方法来保护我们免受垃圾邮件的伤害。