如何在 CherryPy 中为 WTForms 集成验证码 (Recaptcha)
How to integrate Captcha (Recaptcha) for WTForms in CherryPy
我想在我的 WTForms 中使用 RecaptchaField()
,例如:
class MyForm(Form):
name = StringField('Your name', [InputRequired(message='Please enter your name!')])
recaptcha = RecaptchaField() # RecaptchaField as provided by Flask-WTF
submit = SubmitField('Send')
由于我使用的是CherryPy,我不确定是否应该使用Flask-WTF,因为Flask 本身就是一个完整的框架。我想知道我是否可以在我的 CherryPy 解决方案中使用 Flask-WTF 的 Recaptcha 功能。我尝试了以下方法:
from wtforms import StringField
from wtforms.validators import InputReqired
from flask.ext.wtf import Form
from flask.ext.wtf.recaptcha import RecaptchaField
# ...
form = MyForm() # Somewhere in my code
如 this Example here 所示。我得到以下异常:
RuntimeError: working outside of application context
这意味着我必须考虑到正确的上下文来正确设置 Flask 应用程序...这是我开始怀疑我是否采用了正确方法的地方。除了在我的 CherryPy 应用程序中设置一个单独的 Flask 应用程序之外没有其他方法吗??
我的回答主要与问题的 CherryPy 和 reCaptcha 部分相关。在我看来,使用 WTForms 和其他类似库会导致设计问题,就类似 MVC 的设计而言,您将视图和控制器分散到您自己的代码和 WTForms code/configuration 中。当您在一个地方管理一件事时,事情就简单了。因此,我建议在控制器中使用像 Jinja2 for the view (you can create a macro for a repetitive form element) and use input validation library like voluptuous 这样的模板引擎(您可以使用相同的模式进行表单和 API 验证)。
如果你无法避免 WTForms,只需抓住 validateRecaptcha
并将其变成 WTForms custom validator。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import json
import cherrypy
import voluptuous as volu
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
},
'/' : {
'recaptcha' : {
# By default, all keys work on localhost
'siteKey' : '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J',
'secret' : '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu'
}
}
}
def validateRecaptcha(value):
'''https://developers.google.com/recaptcha/docs/verify'''
if 'g-recaptcha-response' not in cherrypy.request.params:
raise volu.Invalid('Recaptcha response is missing')
payload = urllib.urlencode({
'secret' : cherrypy.request.config['recaptcha']['secret'],
'remoteip' : cherrypy.request.headers['remote-addr'],
'response' : cherrypy.request.params['g-recaptcha-response']
})
url = 'https://www.google.com/recaptcha/api/siteverify'
response = json.load(urllib.urlopen(url, payload))
if not response['success']:
cherrypy.log(str(response))
raise volu.Invalid(response['error-codes'])
class App:
@cherrypy.expose
def index(self, **kwargs):
form = dict(form = {'value': ''}, errors = '')
if cherrypy.request.method == 'POST':
schema = volu.Schema({
'value' : volu.All(unicode, volu.Length(min = 8, max = 16)),
'g-recaptcha-response' : validateRecaptcha,
}, required = True, extra = True)
try:
kwargs = schema(kwargs)
except volu.MultipleInvalid as ex:
form = dict(form = kwargs, errors = {e.path[0] for e in ex.errors})
else:
raise cherrypy.HTTPRedirect('#success')
return '''<!DOCTYPE html>
<html>
<head>
<title>reCAPTCHA demo</title>
<script src="https://www.google.com/recaptcha/api.js" type="text/javascript"></script>
</head>
<body>
<form action="/" method="POST">
<div style='border: 1px red solid'>{errors}</div>
<div>Name</div>
<input type="text" name="value" value="{form[value]}"/>
<br/>
<div class="g-recaptcha" data-sitekey="{0}"></div>
<br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
'''.format(cherrypy.request.config['recaptcha']['siteKey'], **form)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
我想在我的 WTForms 中使用 RecaptchaField()
,例如:
class MyForm(Form):
name = StringField('Your name', [InputRequired(message='Please enter your name!')])
recaptcha = RecaptchaField() # RecaptchaField as provided by Flask-WTF
submit = SubmitField('Send')
由于我使用的是CherryPy,我不确定是否应该使用Flask-WTF,因为Flask 本身就是一个完整的框架。我想知道我是否可以在我的 CherryPy 解决方案中使用 Flask-WTF 的 Recaptcha 功能。我尝试了以下方法:
from wtforms import StringField
from wtforms.validators import InputReqired
from flask.ext.wtf import Form
from flask.ext.wtf.recaptcha import RecaptchaField
# ...
form = MyForm() # Somewhere in my code
如 this Example here 所示。我得到以下异常:
RuntimeError: working outside of application context
这意味着我必须考虑到正确的上下文来正确设置 Flask 应用程序...这是我开始怀疑我是否采用了正确方法的地方。除了在我的 CherryPy 应用程序中设置一个单独的 Flask 应用程序之外没有其他方法吗??
我的回答主要与问题的 CherryPy 和 reCaptcha 部分相关。在我看来,使用 WTForms 和其他类似库会导致设计问题,就类似 MVC 的设计而言,您将视图和控制器分散到您自己的代码和 WTForms code/configuration 中。当您在一个地方管理一件事时,事情就简单了。因此,我建议在控制器中使用像 Jinja2 for the view (you can create a macro for a repetitive form element) and use input validation library like voluptuous 这样的模板引擎(您可以使用相同的模式进行表单和 API 验证)。
如果你无法避免 WTForms,只需抓住 validateRecaptcha
并将其变成 WTForms custom validator。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import json
import cherrypy
import voluptuous as volu
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
},
'/' : {
'recaptcha' : {
# By default, all keys work on localhost
'siteKey' : '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J',
'secret' : '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu'
}
}
}
def validateRecaptcha(value):
'''https://developers.google.com/recaptcha/docs/verify'''
if 'g-recaptcha-response' not in cherrypy.request.params:
raise volu.Invalid('Recaptcha response is missing')
payload = urllib.urlencode({
'secret' : cherrypy.request.config['recaptcha']['secret'],
'remoteip' : cherrypy.request.headers['remote-addr'],
'response' : cherrypy.request.params['g-recaptcha-response']
})
url = 'https://www.google.com/recaptcha/api/siteverify'
response = json.load(urllib.urlopen(url, payload))
if not response['success']:
cherrypy.log(str(response))
raise volu.Invalid(response['error-codes'])
class App:
@cherrypy.expose
def index(self, **kwargs):
form = dict(form = {'value': ''}, errors = '')
if cherrypy.request.method == 'POST':
schema = volu.Schema({
'value' : volu.All(unicode, volu.Length(min = 8, max = 16)),
'g-recaptcha-response' : validateRecaptcha,
}, required = True, extra = True)
try:
kwargs = schema(kwargs)
except volu.MultipleInvalid as ex:
form = dict(form = kwargs, errors = {e.path[0] for e in ex.errors})
else:
raise cherrypy.HTTPRedirect('#success')
return '''<!DOCTYPE html>
<html>
<head>
<title>reCAPTCHA demo</title>
<script src="https://www.google.com/recaptcha/api.js" type="text/javascript"></script>
</head>
<body>
<form action="/" method="POST">
<div style='border: 1px red solid'>{errors}</div>
<div>Name</div>
<input type="text" name="value" value="{form[value]}"/>
<br/>
<div class="g-recaptcha" data-sitekey="{0}"></div>
<br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
'''.format(cherrypy.request.config['recaptcha']['siteKey'], **form)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)