我想在我的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应用程序之外没有其他办法吗?
答案 0 :(得分:1)
我的回答主要与CherryPy和问题的reCaptcha部分有关。在我看来,使用WTForms和其他类似的库会导致设计问题,当谈到类似MVC的设计时,您将视图和控制器分散到您自己的代码和WTForms代码/配置中。当你在一个地方管理一件事情时,事情很简单。因此,我建议使用Jinja2之类的模板引擎作为视图(您可以为重复的表单元素创建一个宏)并在控制器中使用输入验证库,如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)