【问题标题】:How to validate Google reCAPTCHA v2 in django如何在 django 中验证 Google reCAPTCHA v2
【发布时间】:2015-06-15 09:55:35
【问题描述】:

我一直在尝试在我制作的网站上使用 Google reCAPTCHA。验证码加载到网页上,但我无法使用多种方法对其进行验证。我已经使用给出的方法尝试了 recaptcha 验证 How to use Python plugin reCaptcha client for validation? 但我认为它已经过时了,因为它不再有效,它指的是挑战,而我尝试使用的是谷歌新的“复选框”reCAPTCHA v2,或者我可能需要在安装后更改我的设置recaptcha-client 或 django-recaptcha。

请帮忙!

【问题讨论】:

    标签: python django validation recaptcha


    【解决方案1】:

    这里有一个第三方 Django 应用来实现新的 reCAPTCHA v2:

    https://github.com/ImaginaryLandscape/django-nocaptcha-recaptcha

    安装完成后,将以下行添加到以下文件中:

    # settings.py
    NORECAPTCHA_SITE_KEY = <the Google provided site_key>
    NORECAPTCHA_SECRET_KEY = <the Google provided secret_key>
    
    INSTALLED_APPS = (
        ....
        'nocaptcha_recaptcha'
    )
    
    
    #forms.py
    from nocaptcha_recaptcha.fields import NoReCaptchaField
    
    class YourForm(forms.Form):
        .....
        captcha = NoReCaptchaField()
    
    
    # In your template, add the following script tag:
    <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    

    【讨论】:

    • 我试过这个。该字段未在我的 html 模板中呈现。我正在使用一个自定义表单,它为我的 django 表单提供数据,并且我使用了一个单独的表单来使用 django {{ from.as_p }},但它不会呈现。虽然,表单已停止注册,所以我知道它正在工作并且只剩下渲染。
    • 在这种情况下,我建议提出一个与您的问题相关的新的、具体的问题。您当前的问题询问您如何使用 Django 设置 reCAPTCHA v2(补充说您已经尝试过为 reCAPTCHA v1 设计的 reCAPTCHA 应用程序),这回答了这个问题。您应该发布一个单独的问题,列出您的具体问题、代码以及您已完成的故障排除。如果您愿意,您也可以将此答案标记为对现有问题的正确答案,以便其他找到它的人受益。
    【解决方案2】:

    这是一个使用requests 库 (http://docs.python-requests.org/en/latest/) 在 Django 视图中验证 Google reCAPTCHA v2 的简单示例:

    import requests
    from django.conf import settings
    
    def get_client_ip(request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def grecaptcha_verify(request):
        if request.method == 'POST':
            response = {}
            data = request.POST
            captcha_rs = data.get('g-recaptcha-response')
            url = "https://www.google.com/recaptcha/api/siteverify"
            params = {
                'secret': settings.RECAPTCHA_SECRET_KEY,
                'response': captcha_rs,
                'remoteip': get_client_ip(request)
            }
            verify_rs = requests.get(url, params=params, verify=True)
            verify_rs = verify_rs.json()
            response["status"] = verify_rs.get("success", False)
            response['message'] = verify_rs.get('error-codes', None) or "Unspecified error."
            return HttpResponse(response)
    

    【讨论】:

    • 什么时候调用grecaptcha_verify方法?
    • @AkaSh 我曾经在调用form.is_valid() 方法之前调用该方法。
    【解决方案3】:

    Google 改变了 API,我们现在需要使用 POST 请求。如果您需要在多个 django 视图中进行验证,这是一个可重复使用的解决方案:

    utils.py

    # django imports
    from django.conf import settings
    from django.views.generic.base import View
    from django.http import HttpResponseForbidden
    
    # 3rd-party imports
    import requests
    from ipware import get_client_ip
    
    
    def is_recaptcha_valid(request):
        """
        Verify if the response for the Google recaptcha is valid.
        """
        return requests.post(
            settings.GOOGLE_VERIFY_RECAPTCHA_URL,
            data={
                'secret': settings.RECAPTCHA_SECRET_KEY,
                'response': request.POST.get('g-recaptcha-response'),
                'remoteip': get_client_ip(request)
            },
            verify=True
        ).json().get("success", False)
    
    
    
    def human_required(view_func):
        """
        This decorator is aimed to verify Google recaptcha in the backend side.
        """
        def wrapped(request, *args, **kwargs):
            if is_recaptcha_valid(request):
                return view_func(request, *args, **kwargs)
            else:
                return HttpResponseForbidden()
        return wrapped
    

    然后:

    views.py

     from utils import human_required
    
     class MyView(View):
    
         @human_required
         def post(request, *args, **args):
            pass
    

    请注意,我们在此解决方案中使用django-ipware 来获取 IP 地址,但这取决于您。另外,不要忘记将GOOGLE_VERIFY_RECAPTCHA_URLRECAPTCHA_SECRET_KEY 添加到django 设置文件中!

    【讨论】:

    • 我认为如果 POST 中不存在“g-recaptcha-response”,则立即返回 False 是一个好主意。
    • 是的,我同意!蒂姆
    【解决方案4】:

    views.py

    ​​>
    def login(request):
        if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = auth.authenticate(request, username=username, password=password)
    
         if user is not None:
            if user.is_active:
                auth.login(request, user)
                ''' Begin reCAPTCHA validation '''
                recaptcha_response = request.POST.get('g-recaptcha-response')
                url = 'https://www.google.com/recaptcha/api/siteverify'
                values = {
                'secret' : settings.GOOGLE_RECAPTCHA_SECRET_KEY,
                'response' :  recaptcha_response
                }
                data = urllib.parse.urlencode(values).encode("utf-8")
                req = urllib2.Request(url, data)
                response = urllib2.urlopen(req)
                result = json.load(response)
                ''' End reCAPTCHA validation '''
    
                if result['success']:
                  return redirect('index')
                else:
                  messages.error(request, 'Invalid reCAPTCHA. Please try again.')
                  return redirect('login')
        else:
            messages.info(request, 'Wrong Credentials!!! enter right username or password')
            return redirect('login')
    else:
        return render(request, 'login.html')
    

    login.html

    <form action="{% url 'login' %}" method="post">
                {% csrf_token %}
                <div class="body bg-gray">
                    <div class="form-group">
                        <input type="text" name="username" class="form-control" placeholder="Username"/>
                    </div>
                    <div class="form-group">
                        <input type="password" name="password" class="form-control" placeholder="Password"/>
                    </div>          
                    <div class="form-group">
                        <input type="checkbox" name="remember_me"/> Remember me
                    </div>
                </div>
                <div class="footer">                                                               
                     <button type="submit" class="btn bg-olive btn-block">Sign me in</button>
    
                    <p><a href="#">I forgot my password</a></p>
    
                    <a href="{% url 'register' %}" class="text-center">Register a new membership</a>
                </div>
                <br><br>
                <script src='https://www.google.com/recaptcha/api.js'></script>
                <div class="g-recaptcha" data-sitekey="(enter your key here that is private or authenticated on google recapthcha)"></div>
            </form>
    

    settings.py

    ​​>
    INSTALLED_APPS = [
       ....
       ....
       'captcha'
                   ]
    
    GOOGLE_RECAPTCHA_SECRET_KEY ='6LdXBLAUAMlGYqqyDESeHKI7-'
    RECAPTCHA_PUBLIC_KEY = '6LdXBLAUAAAAAP3oI1VPJgA-VHXoj'
    RECAPTCHA_PRIVATE_KEY = '6LdXBLAUAAAAAGYqqyDESeHKI7-'
    
    ''' you have to register your domain to get the access of these keys. or you can 
    register your localhost also to test this after uploading on the server you can 
    register with real domain and change the keys.
    
    don't forget to like if you find it helpful.'''
    
     'https://www.google.com/recaptcha/intro/v3.html' -> 'admin console' where you can 
     register your domain or localhost and get your key. 
    

    【讨论】:

    • 欢迎来到 SO!感谢您提供如此出色的答案。如果您可以包含一些关于您为达到预期结果所做的工作的额外 cmets,那就太好了。
    【解决方案5】:

    扩展 @trinchet 给出的答案,这里是 FormView Django 类的简单修改,以自动处理 Google 的 reCAPTCHA v2。

    class RecaptchaFormView(FormView):
        """ This class handles Google's reCAPTCHA v2. """
        recaptcha_ok = None
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['grecaptcha_site_key'] = settings.RECAPTCHA_SITE_KEY
            return context
    
        def get_form(self):
            form = super().get_form()
            if self.recaptcha_ok == False:
                form.add_error(None, "Invalid reCAPTCHA, please try again.")
            return form
    
        def post(self, request, *args, **kwargs):
            self.recaptcha_ok = is_recaptcha_valid(request)
            return super().post(self, request, *args, **kwargs)
    

    不要忘记包含@trinchet 提供的 is_recaptcha_valid 函数(请参阅他的答案)、settings.py 中的 reCAPTCHA 键和模板中的 reCAPTCHA 代码(使用 {{ grecaptcha_site_key }} 作为站点键)。

    【讨论】:

      【解决方案6】:

      这就是我处理提出的问题的方式:

      views.py

      from django.contrib.auth.views import LoginView, LogoutView
      from django.conf import settings
      
      from authentication.forms import MyAuthenticationForm
      
      
      class MyLoginView(LoginView):
         template_name = 'authentication/login.html'
         form_class = MyAuthenticationForm
      
         def get_client_ip(self):
             x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
             if x_forwarded_for:
                 ip = x_forwarded_for.split(',')[0]
             else:
                 ip = self.request.META.get('REMOTE_ADDR')
             return ip
      
         def get_form_kwargs(self):
             kwargs = super(MyLoginView, self).get_form_kwargs()
             if self.request.method in 'POST':
                 kwargs['g-recaptcha-response'] = self.request.POST.get('g-recaptcha-response')
                 kwargs['remote_ip'] = self.get_client_ip()
             return kwargs
      
         def get_context_data(self, **kwargs):
             context = super(MyLoginView, self).get_context_data(**kwargs)
             # To use in the template
             context['recaptcha_challenge_secret'] = settings.G_RECAPTCHA_CHALLENGE_SECRET
             return context
      
      

      forms.py

      import requests
      
      from django.contrib.auth.forms import AuthenticationForm
      from django.conf import settings
      from django.forms import ValidationError
      from django.utils.translation import ugettext_lazy as _
      
      
      class MyAuthenticationForm(AuthenticationForm):
          def __init__(self, *args, **kwargs):
              self.g_recaptcha_response = kwargs.pop('g-recaptcha-response', None)
              self.remote_ip = kwargs.pop('remote_ip', None)
              super(MyAuthenticationForm, self).__init__(*args, **kwargs)
      
          def clean(self):
              cleaned_data = super(MyAuthenticationForm, self).clean()
              self.verify_captcha()
              return cleaned_data
      
          def verify_captcha(self):
              if self.g_recaptcha_response:
                  data = {
                      'secret': settings.G_RECAPTCHA_VERIFY_SECRET,
                      'response': self.g_recaptcha_response,
                      'remoteip': self.remote_ip
                  }
      
                  response = requests.post(settings.G_RECAPTCHA_VERIFICATION_URL, data=data)
                  result = response.json()
      
                  if result['success']:
                      return
      
              raise ValidationError(
                  _('Invalid reCAPTCHA challenge.'),
                  code='invalid_recaptcha_challenge'
              )
      

      【讨论】:

        猜你喜欢
        • 2015-03-10
        • 1970-01-01
        • 2019-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-05
        • 1970-01-01
        相关资源
        最近更新 更多