You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django DRF服务端校验reCAPTCHA响应 验证通过才允许数据入库

问题根因

你现在的代码有几个硬伤,直接导致校验完全失效:

  • 请求取值逻辑错了:前端发的是application/json格式的请求,request.POST只接收form-urlencoded、form-data类型的请求体,你写的request.POST.get('g-recaptcha-response')永远拿不到值,手写的那堆校验逻辑从根上就取不到验证码token,等于白写
  • 配置名写错:settings里给drf-recaptcha配的密钥变量是DRF_RECAPTCHA_SECRET_KEY,手写校验里取的是GOOGLE_RECAPTCHA_SECRET_KEY,俩名字对不上,就算拿到token也会因为密钥不对校验失败
  • 重复造轮子还漏了拦截分支:你已经在序列化器里加了ReCaptchaField,根本不需要自己手写代码调用谷歌校验接口,而且你手写的逻辑只处理了校验成功的分支,校验失败的时候没有任何拦截返回,逻辑有缺口
  • 字段名对不上:序列化器里验证码字段叫recaptcha,你手动取的参数名是g-recaptcha-response,前端如果没把token传到recaptcha字段里,序列化器自带的校验也触发不了
  • 代码版本不兼容:视图里用的urllib/urllib2是Python2的写法,Python3环境下跑这段直接报错,校验逻辑根本执行不下去
正确实现方案

直接用drf-recaptcha自带的校验能力即可,不需要自己手写请求调用校验接口,改四个地方就行:

1. 修正settings.py配置

确保配置的密钥名和drf-recaptcha要求的一致,不要自定义变量名:

INSTALLED_APPS = [
    # 你的其他业务应用
    'rest_framework',
    'rest_framework_recaptcha',
]
# 变量名必须是DRF_RECAPTCHA_SECRET_KEY,不要随意修改
DRF_RECAPTCHA_SECRET_KEY = '<你的reCAPTCHA服务端密钥>'

2. 修正序列化器

如果你的Contact数据表本身没有recaptcha字段,要加write_only=True参数,避免序列化器保存时报字段不存在的错误,验证码字段只做写入校验,不需要存入数据库:

from rest_framework import serializers
from rest_framework_recaptcha import ReCaptchaField
from .models import Contact

class ContactSerializer(serializers.ModelSerializer):
    recaptcha = ReCaptchaField(write_only=True)
    class Meta:
        model = Contact
        fields = '__all__'

3. 简化视图逻辑,删除冗余手写校验代码

drf-recaptcha的字段会在serializer.is_valid()阶段自动完成验证码校验,校验不通过会直接返回错误,根本不会走到数据保存逻辑:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import ContactSerializer

@api_view(['POST', 'GET'])
def contact_forms_api(request):
    if request.method == 'POST':
        serializer = ContactSerializer(data=request.data)
        # is_valid()会自动校验recaptcha字段,验证码无效、过期、为空都会直接抛错,不会执行save
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response({
                'status': True,
                'message': '提交成功'
            })
    # GET请求逻辑自行补充,比如返回历史提交记录
    return Response({
        'status': False,
        'message': '请求方式不合法'
    })

4. 修正前端提交逻辑

确保把react-google-recaptcha拿到的token,放在请求体的recaptcha字段里,和后端序列化器字段名完全对应:

import { useState } from 'react'
import ReCAPTCHA from 'react-google-recaptcha'
import axios from 'axios'

export default function ContactForm() {
  // 存储验证码token
  const [recaptchaToken, setRecaptchaToken] = useState('')

  // 验证码加载完成的回调
  const handleRecaptcha = (token) => {
    setRecaptchaToken(token)
  }

  // 表单提交逻辑
  const SubmitContact = async (e) => {
    e.preventDefault()
    // 组装表单数据,替换成你实际的表单字段
    const formData = {
      name: e.target.name.value,
      contact: e.target.contact.value,
      content: e.target.content.value,
      recaptcha: recaptchaToken // 字段名必须为recaptcha,和后端对齐
    }
    // 发送请求
    await axios.post('/api/contact', formData, {
      headers: { 'Content-Type': 'application/json' }
    })
  }

  return (
    <form onSubmit={SubmitContact}>
      <input type="text" name="name" placeholder="姓名" />
      <input type="text" name="contact" placeholder="联系方式" />
      <textarea name="content" placeholder="留言内容"></textarea>
      <ReCAPTCHA
        sitekey="<你的前端reCAPTCHA sitekey>"
        onChange={handleRecaptcha}
      />
      <button type="submit">提交</button>
    </form>
  )
}
校验逻辑说明

改完之后逻辑是完全闭环的:

  • 用户没勾选验证码,recaptchaToken为空,后端序列化器校验直接返回recaptcha字段不能为空的错误,不会执行入库操作
  • 用户传的验证码token无效、过期,drf-recaptcha会自动调用reCAPTCHA服务端接口校验,校验失败直接返回错误,不会入库
  • 只有验证码校验通过、其他表单字段也符合规则的情况下,才会执行serializer.save()把数据写入数据库

注意:如果服务部署在国内,要确保你的服务器能正常访问reCAPTCHA的校验接口,不然会出现接口超时、校验失败的问题。

内容的提问来源于stack exchange,提问作者boyenec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:57:29