Flask-wtf:csrf_token 在我可以 POST 我的表单之前从会话中删除
Flask-wtf: csrf_token is removed from session before I can POST my form
我将 Flask 与 Flask-Security(特别是关于我的 csrf 问题的 Flask-WTF)一起用于 "ease" register/loggin 用户的进程(到目前为止并不容易)。我在前端使用 BackboneJS,因此我破解了使用 Flask-WTF 的原始方法。实际上,我在 /register 上发出 AJAX GET 请求以获取注册页面(由 Flask-Security 生成),然后将结果 HTML 放入模式中。
render: function () {
var self = this;
$.ajax({
type: 'GET',
url: Config.constants.serverGateway + "/register"
}).done(function(result){
console.log("get register done", result);
var html = self.template({ config: Config, form: result });
self.$el.html(html);
}).fail(function(error){
console.log("Could not get register token", error);
var html = this.errorTemplate({ config: Config });
self.$el.html(html);
});
return this;
}
这样我就有了生成的 csrf,当我 POST 注册数据时,我发送了正确的 csrf 以及用户数据(电子邮件和密码)。
submit: function () {
console.log("submit");
var self = this;
var formData = this.$el.find('form').serialize();
$.ajax({
type: 'POST',
url: Config.constants.serverGateway + "/register",
data: formData,
dataType: 'json'
}).done(function(result){
self.trigger('close');
}).fail(function(error){
console.log("Could not submit register data", error);
});
}
在服务器端,我可以调试我的python代码,看到当我请求注册页面时生成的csrf_token已经从会话对象中消失,因此导致生成一个新的,这当然与我随表格发送的不匹配。会话仍然相同,因为 _id 在 GET 和 POST.
期间相同
可以看到flask_wtf/csrf.py::generate_csrf()中的代码,在flask_security/views.py的::register函数中创建表单对象时调用
if 'csrf_token' not in session:
session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()
它会导致 CSRF TOKEN MISSING 错误。
另外一个信息,我的前端和后端是同一个服务器传送的,因为它们有不同的端口号。
最后,当我在前端使用 href 并显示服务器根据 'GET' 请求返回的页面时,提交表单效果很好。我只是喜欢以模式显示此注册表单。
感谢您的帮助
(因为无法发表评论,所以在这里回答)
@junnytony 是的,我的模式中有令牌,我在 POSt 请求中发送了它。当我调试 Flask 应用程序时,我可以看到我用 POST 请求发送的 toekn,问题是它应该与要验证的会话中的相比,但是会话中的那个已经消失了,所以flask-wtf lib生成了一个新的,结果和我发送的比较失败。
好的,我终于找到了解决问题的方法。我觉得自己像个菜鸟(我就是)。
问题在于会话凭据没有随请求发送到服务器,因此服务器无法访问会话 cookie。
我在以下教程中找到了解决方案:http://backbonetutorials.com/cross-domain-sessions/
为了发送它,我在 Backbone 路由器初始化函数中添加了以下几行:
// Use withCredentials to send the server cookies
// The server must allow this through response headers
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.xhrFields = {
withCredentials: true
};
});
这使得所有 AJAX 请求都包含 withCredentials = true
。在服务器端,我必须设置 Access-Control-Allow-Credentials:true
。由于我使用的是 flask-cors,因此在创建 CORS 对象时使用 [supports_credentials=True][2]
完成。
我将 Flask 与 Flask-Security(特别是关于我的 csrf 问题的 Flask-WTF)一起用于 "ease" register/loggin 用户的进程(到目前为止并不容易)。我在前端使用 BackboneJS,因此我破解了使用 Flask-WTF 的原始方法。实际上,我在 /register 上发出 AJAX GET 请求以获取注册页面(由 Flask-Security 生成),然后将结果 HTML 放入模式中。
render: function () {
var self = this;
$.ajax({
type: 'GET',
url: Config.constants.serverGateway + "/register"
}).done(function(result){
console.log("get register done", result);
var html = self.template({ config: Config, form: result });
self.$el.html(html);
}).fail(function(error){
console.log("Could not get register token", error);
var html = this.errorTemplate({ config: Config });
self.$el.html(html);
});
return this;
}
这样我就有了生成的 csrf,当我 POST 注册数据时,我发送了正确的 csrf 以及用户数据(电子邮件和密码)。
submit: function () {
console.log("submit");
var self = this;
var formData = this.$el.find('form').serialize();
$.ajax({
type: 'POST',
url: Config.constants.serverGateway + "/register",
data: formData,
dataType: 'json'
}).done(function(result){
self.trigger('close');
}).fail(function(error){
console.log("Could not submit register data", error);
});
}
在服务器端,我可以调试我的python代码,看到当我请求注册页面时生成的csrf_token已经从会话对象中消失,因此导致生成一个新的,这当然与我随表格发送的不匹配。会话仍然相同,因为 _id 在 GET 和 POST.
期间相同可以看到flask_wtf/csrf.py::generate_csrf()中的代码,在flask_security/views.py的::register函数中创建表单对象时调用
if 'csrf_token' not in session:
session['csrf_token'] = hashlib.sha1(os.urandom(64)).hexdigest()
它会导致 CSRF TOKEN MISSING 错误。
另外一个信息,我的前端和后端是同一个服务器传送的,因为它们有不同的端口号。
最后,当我在前端使用 href 并显示服务器根据 'GET' 请求返回的页面时,提交表单效果很好。我只是喜欢以模式显示此注册表单。
感谢您的帮助
(因为无法发表评论,所以在这里回答) @junnytony 是的,我的模式中有令牌,我在 POSt 请求中发送了它。当我调试 Flask 应用程序时,我可以看到我用 POST 请求发送的 toekn,问题是它应该与要验证的会话中的相比,但是会话中的那个已经消失了,所以flask-wtf lib生成了一个新的,结果和我发送的比较失败。
好的,我终于找到了解决问题的方法。我觉得自己像个菜鸟(我就是)。
问题在于会话凭据没有随请求发送到服务器,因此服务器无法访问会话 cookie。 我在以下教程中找到了解决方案:http://backbonetutorials.com/cross-domain-sessions/ 为了发送它,我在 Backbone 路由器初始化函数中添加了以下几行:
// Use withCredentials to send the server cookies
// The server must allow this through response headers
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.xhrFields = {
withCredentials: true
};
});
这使得所有 AJAX 请求都包含 withCredentials = true
。在服务器端,我必须设置 Access-Control-Allow-Credentials:true
。由于我使用的是 flask-cors,因此在创建 CORS 对象时使用 [supports_credentials=True][2]
完成。