Django-将Google Recaptcha v2添加到登录表单

时间:2019-02-27 11:46:20

标签: python django recaptcha

我正在尝试将Recaptcha添加到Django中的登录表单中。我尝试了不同的库,但似乎都不起作用,因为验证码表单只是没有出现在模板中。

这是我当前的工作:

urls.py

path(r'captcha/', include('captcha.urls'))

forms.py

class NewUserForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class YourForm(forms.Form):
        captcha = CaptchaField()

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

    def save(self, commit=True):
        user = super(NewUserForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        if commit:
            user.save()
        return user

这是我的 login.html 模板

<form action="/your-name/" method="post">
   {% csrf_token %}
   {{ form.captcha }}
   <input type="submit" value="Submit">
</form>

在这种情况下,只会显示Submit按钮,而不会显示captcha表单。这是我尝试过的任何其他库所发生的事情。谁能给我些帮助吗?预先感谢!

2 个答案:

答案 0 :(得分:4)

很难直接提供帮助,因为您没有提到要使用的库。这是我在Django登录中添加v2验证码的方法,不需要其他库。

在此示例中,我将recaptcha脚本添加到django登录模板中,并覆盖django auth应用的登录视图,以扩展其功能,以便验证Recaptcha服务器端(使用根据{{3的适当RECAPTCHA_SECRET }}。

还要注意,context_processor用于在登录模板中插入RECAPTCHA_SITE_KEY。

login.html

...
<head>
   <script src="https://www.google.com/recaptcha/api.js" async defer</script>
<script>
  function onSubmit(token) {
    document.getElementById("theForm").submit();
  }
</script>
</head>
<body>
<form id="theForm">
<button class="g-recaptcha btn btn-primary" 
        data-callback="onSubmit" 
        data-sitekey="{{RECAPTCHA_SITE_KEY}}" 
        type="submit">Login
</button>
</form>
</body>
...

url.py

...
# overriding auth app endpoint 
url(r'^accounts/login/', MyLoginView.as_view(), name='login'),
...

context_processor.py

from django.conf import settings 


def recaptcha_site_key(request):
    return {'RECAPTCHA_SITE_KEY': settings.RECAPTCHA_SITE_KEY}

settings.py

TEMPLATES = [
  {
    ...
    'OPTIONS': {
        'context_processors': [
            ...
            'yourapp.context_processors.recaptcha_site_key',
            ...
        ],
    },
  },
]

MyLoginView.py

from django.contrib.auth import views as auth_views

def _validate_recaptcha(token, ip):
    # implement server side validation according to google docs
    pass    

class MyLoginView(auth_views.LoginView):
'''Use django login flow, with added logic for google recaptcha
'''
    def form_valid(self, form):

        request_body = self.request.POST
        if not request_body:
            return None

        recaptcha_token = request_body['g-recaptcha-response']
        ip_addr, _ = get_client_ip(self.request)
        if not _validate_recaptcha(recaptcha_token, ip_addr):
            # your logic
            return redirect('login')

    return super().form_valid(form)

答案 1 :(得分:4)

@ knopch1425建议仅在成功登录后才会使验证码令牌无效。

The LoginView form implementation指出仅在成功登录后才调用form_valid方法

def form_valid(self, form):
    """Security check complete. Log the user in."""
    auth_login(self.request, form.get_user())
    return HttpResponseRedirect(self.get_success_url())

相反,您可以按以下方式覆盖post方法

def post(self, request, *args, **kwargs):
    request_body = self.request.POST
    if not request_body:
        return None

    recaptcha_token = request_body['g-recaptcha-response']
    ip_addr, _ = get_client_ip(self.request)
    if not _validate_recaptcha(recaptcha_token, ip_addr):
        # your logic
        return redirect('login')

    return super().post(self, request, *args, **kwargs)