장고 사이트에 reCAPTCHA 넣기
Add reCAPTCHA to Django site
각종 봇과 스팸으로부터 사이트를 보호하기 위해 구글의 reCATCHA 를 많이 사용하는데요. 본 포스팅에서는 장고로 만들어진 사이트에 이를 손쉽게 적용해보는 방법을 살펴겠습니다.
1. Requirements
1) reCAPTCHA > Get reCAPTCHA 클릭하여 다음과 같이 키를 획득한다.
사이트 등록이 끝나면 2개의 키를 받게 되는데 Site key와 Secret key가 바로 그것이다. 여기서 Site key(사이트와 사용자간)는 원하는 페이지에 렌더링하기 위해 사용되고, Secret key(사이트와 구글간 통신)는 settings.py 모듈에 등록하여 구글과 사이트 간의 통신을 위해 사용된다.
2) settings.py 파일에 아래와 같이 reCAPTCHA 키를 넣는다.
settings.py
1 2 | RECAPTCHA_PUBLIC_KEY = 'MyRecaptchaKey123' RECAPTCHA_PRIVATE_KEY = 'MyRecaptchaPrivateKey456' | cs |
2. Implementing the reCAPTCHA
reCAPTCHA 위젯을 구현하는 가장 손쉬운 방법은 아래와 같이 자바스크립트와 g-recaptcha 태그를 필요한 부분에 넣는 것이다. g-recaptcha 태그는 class name이 'g-recaptcha' 인 DIV 요소이며, data-sitekey 는 앞서 발급받은 Site Key이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <html> <head> <title>reCAPTCHA demo: Simple page</title> <script src="https://www.google.com/recaptcha/api.js" async defer></script> </head> <body> <form action="?" method="POST"> <div class="g-recaptcha" data-sitekey="your_site_key"></div> <br/> <input type="submit" value="Submit"> </form> </body> </html> | cs |
1 2 3 | <script src='https://www.google.com/recaptcha/api.js'></script> <div class="g-recaptcha" data-sitekey="******************************************"> </div> | cs |
구현된 모습은 아래와 같다.
3. Validating the reCAPTCHA
마지막 남은 작업은 https://www.google.com/recaptcha/api/siteverify 로 POST 요청을 보내 데이터가 유효한지 검증하는 것이다.
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import json import urllib from django.shortcuts import render, redirect from django.conf import settings from django.contrib import messages from .models import Questions from .forms import QuestionCreationForm def questions_ask(request): if request.method == 'POST': form = QuestionCreationForm(request.POST) if form.is_valid(): recaptcha_response = request.POST.get('g-recaptcha-response') url = 'https://www.google.com/recaptcha/api/siteverify' values = { 'secret': settings.RECAPTCHA_PRIVATE_KEY, 'response': recaptcha_response } data = urllib.parse.urlencode(values).encode() req = urllib.request.Request(url, data=data) response = urllib.request.urlopen(req) result = json.loads(response.read().decode()) if result['success']: form.save() messages.success(request, 'New question added with success!') return HttpResponseRedirect("/questions") else: messages.error(request, 'Invalid reCAPTCHA. Please try again.') return HttpResponseRedirect("/questions/ask") else: form = QuestionCreationForm() return render(request, "/questions_ask.html", { 'form': form, }) | cs |
questions_ask.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <div class="row"> <div class="col-sm-11 offset-sm-1"> <div class="form-group"> <textarea class="form-control" name="body" rows="12" placeholder="Click here to ask"></textarea> </div> <script src='https://www.google.com/recaptcha/api.js'></script> <div class="g-recaptcha" data-sitekey="*****************************************"> </div> <div><p> </div> <div class="form-group"> <button type="submit" class="btn btn-success">Save changes</button> </div> </div> </div> | cs |
g-recaptcha tag attributes and grecaptcha.render parameters
g-recaptcha tag attribute | grecaptcha.render parameter | Value | Default | Description |
---|---|---|---|---|
data-sitekey | sitekey | Your sitekey. | ||
data-theme | theme | dark light | light | Optional. The color theme of the widget. |
data-type | type | audio image | image | Optional. The type of CAPTCHA to serve. |
data-size | size | compact normal | normal | Optional. The size of the widget. |
data-tabindex | tabindex | 0 | Optional. The tabindex of the widget and challenge. If other elements in your page use tabindex, it should be set to make user navigation easier. | |
data-callback | callback | Optional. The name of your callback function to be executed when the user submits a successful CAPTCHA response. The user's response, g-recaptcha-response , will be the input for your callback function. | ||
data-expired-callback | expired-callback | Optional. The name of your callback function to be executed when the recaptcha response expires and the user needs to solve a new CAPTCH |
https://developers.google.com/recaptcha/docs/display
data-theme 값을 통해 테마의 색상 선택이 가능하다
data-theme="dark"
data-theme="light" (default value)
4. reCAPTCHA Decorator
마지막으로 reCAPTCHA를 데코레이터로 등록하여 사용하는 방법이다.
decorators.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from functools import wraps from django.conf import settings from django.contrib import messages import requests def check_recaptcha(view_func): @wraps(view_func) def _wrapped_view(request, *args, **kwargs): request.recaptcha_is_valid = None if request.method == 'POST': recaptcha_response = request.POST.get('g-recaptcha-response') data = { 'secret': settings.RECAPTCHA_PRIVATE_KEY, 'response': recaptcha_response } r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data) result = r.json() if result['success']: request.recaptcha_is_valid = True else: request.recaptcha_is_valid = False messages.error(request, 'Invalid reCAPTCHA. Please try again.') return view_func(request, *args, **kwargs) return _wrapped_view | cs |
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from django.shortcuts import render, redirect from django.conf import settings from django.contrib import messages from .decorators import check_recaptcha from .models import Answers from .forms import AnswerCreationForm @check_recaptcha def answers_new(request): if request.method == 'POST': form = AnswerCreationForm(request.POST) if form.is_valid() and request.recaptcha_is_valid: answer_obj.save() messages.success(request, 'New Answer added with success!') return redirect('app.views.questions_view', question.pk) else: return redirect('app.views.questions_view', question.pk) else: form = QuestionCreationForm() return render(request, "app/questions_view.html", { 'form': form, }) | cs |
questions_view.html
1 2 3 4 5 6 7 8 | {% if messages %} {% for message in messages %} <font color="red">{{ message }}</font> {% endfor %} {% endif %} <script src='https://www.google.com/recaptcha/api.js'></script> <div class="g-recaptcha" data-sitekey="*******************" data-theme="light"></div> | cs |
'프로그래밍 Programming' 카테고리의 다른 글
OSError : setuptools pip wheel failed with error code 1 (0) | 2017.04.14 |
---|---|
conda vs. pip vs. virtualenv (0) | 2017.04.13 |
Django와 Handsontable.js를 이용한 엑셀풍의 입력화면 만들기 (0) | 2017.03.30 |
Handsontable 기본 사용법 (0) | 2017.03.25 |
Django Channels로 채팅룸 만들기 (0) | 2017.02.21 |