Skip to content

Instantly share code, notes, and snippets.

@mywaiting
Created July 4, 2014 14:29
Show Gist options
  • Save mywaiting/ce9e463f6a02826234c1 to your computer and use it in GitHub Desktop.
Save mywaiting/ce9e463f6a02826234c1 to your computer and use it in GitHub Desktop.
Tornado-Recaptcha
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
import urllib.parse as urllib_parse # py3
except ImportError:
import urllib as urllib_parse # py2
import tornado
import tornado.concurrent
import tornado.escape
import tornado.gen
import tornado.httpclient
from tornado.escape import utf8, to_unicode, to_basestring
class RecaptchaError(Exception):
pass
class RecaptchaResponse(object):
def __init__(self, is_valid, error_code=None):
self.is_valid = is_valid
self.error_code = error_code
class RecaptchaMixin(object):
_RECAPTCHA_BASE_URL = u"https://www.google.com/recaptcha"
_RECAPTCHA_API_URL = u"https://www.google.com/recaptcha/api"
_RECAPTCHA_VERIFR_URL = u"https://www.google.com/recaptcha/api/verify"
# @tornado.concurrent.return_future
def recaptcha_request(self, private_key, callback=None, **kwargs):
recaptcha_challenge_field = self.get_argument("recaptcha_challenge_field", None)
recaptcha_response_field = self.get_argument("recaptcha_response_field", None)
remote_ip = self.request.remote_ip
# if not recaptcha_challenge_field and not recaptcha_response_field:
# future.set_result(RecaptchaResponse(is_valid=False, error_code=""))
data = urllib_parse.urlencode({
"private_key": self.private_key,
"remoteip": remote_ip,
"challenge": recaptcha_challenge_field,
"response": recaptcha_response_field
})
request = tornado.httpclient.HTTPRequest(url=self._RECAPTCHA_VERIFR_URL,
method="POST",
headers={
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "reCAPTCHA-Client"
},
body=data,
validate_cert=False)
# client = self._get_http_client()
client = tornado.httpclient.AsyncHTTPClient()
request_callback = self.async_callback(self._on_recaptcha_request, callback)
client.fetch(request, callback=request_callback)
# callback
def _on_recaptcha_request(self, future, response):
if response.error:
future.set_exception(RecaptchaError(
"Error response %s fetching %s" %(response.error, response.request.url)))
return
parts = response.body.spilt("\n")
if parts[0] == "true":
ret = RecaptchaResponse(is_valid=True, error_code=None)
else:
ret = RecaptchaResponse(is_valid=False, error_code=parts[1])
future.set_result(ret)
# def _get_http_client(self):
# return tornado.httpclient.AsyncHTTPClient()
# UIModule
class RecaptchaModule(tornado.web.UIModule):
def render(self, recaptcha_public_key, recaptcha_error):
"""Custom theme:
https://github.com/chrisvanpatten/responsive-recaptcha
"""
if recaptcha_error:
error_param = "&error=%s" % recaptcha_error
else:
error_param = ""
return """
<script type="text/javascript">
var RecaptchaOptions = {
custom_translations : {
instructions_visual : "请输入上图的图片验证码",
instructions_audio : "请输入你听到的声音验证码",
play_again : "重新播放验证码声音",
cant_hear_this : "是否无法听到此MP3声音?下载回来收听!",
visual_challenge : "查看图片验证码",
audio_challenge : "播放声音验证码",
refresh_btn : "刷新换个验证码",
help_btn : "关于此验证码",
incorrect_try_again : "你输入的验证码不正确,请重新输入",
},
lang: 'en',
theme : 'clean'
};
</script>
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=%(PublicKey)s%(ErrorParam)s"></script>
<noscript>
<iframe src="https://www.google.com/recaptcha/api/noscript?k=%(PublicKey)s%(ErrorParam)s" height="300" width="500" frameborder="0"></iframe><br />
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type='hidden' name='recaptcha_response_field' value='manual_challenge' />
</noscript>
""" % {
"PublicKey": recaptcha_public_key,
"ErrorParam": error_param,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment