我花了几个小时调试 Flask-WTF 的验证问题。与许多其他问题一样,问题是 CSRF 验证问题。但是,我的问题不是由我发现的任何常见问题引起的。
CSRF 的标准 Flask-WTF 实现需要将两件事传递给浏览器。
一:隐藏的 CSRF 表单域 eg
<input id="csrf_token" name="csrf_token" type="hidden" value="ImYzODdmZTdhYTRlMmNkYWRjYmRlYWFmZjQxMDllZTQ1OWZmYzg3MTki.XKvOPg.gUCkF9j-vg0PrL2PRH-v43GeHu0">
二:会话cookie HTTP响应头 例如
Set-Cookie: session=eyJjc3JmX3Rva2VuIjoiZjM4N2ZlN2FhNGUyY2RhZGNiZGVhYWZmNDEwOWVlNDU5ZmZjODcxOSJ9.XKvOPg.a3-W62MHvaGVkv2GYCi-dgpLE3Y; HttpOnly; Path=/
如果缺少其中任何一个,浏览器将无法发送正确的 CSRF 验证。当然,这反过来会导致表单验证失败。
如果csrf_token
表单中存在隐藏字段但缺少会话cookie,则提交表单时您将收到以下响应...
Bad Request
The CSRF session token is missing.
在我的情况下,由于我的代码中的错误,会话 cookie 丢失了。我需要在整个 Flask 站点中提供自定义 HTTP 标头。我像这样包含它...
class LocalFlask(Flask):
def process_response(self, response):
response.headers['my-header'] = 'My Header Value'
return response
app = LocalFlask(__name__)
然而,这会导致任何依赖该Flask.response.headers
方法的东西失败。其中之一是 Flaks-WTF 设置会话 cookie HTTP 标头。
这可以通过将super()
方法添加到LocalFlask
类中来解决,以便它继承Flask
类的方法。
class LocalFlask(Flask):
def process_response(self, response):
response.headers['my-header'] = 'My Header Value'
#LocalFlask inherits methods from Flask
super(LocalFlask, self).process_response(response)
return response
app = LocalFlask(__name__)