我正在使用nodejs并且通常传递csrf令牌,如下所示:
util.js中
module.exports.csrf = function csrf(req, res, next){
res.locals.token = req.csrfToken();
next();
};
app.js
app.use(csrf());
app.use(util.csrf);
然后在ejs页面中我会做
<input type="hidden" name="_csrf" value="<%= token %>">
但是,现在我正在使用flux / react作为我的前端,需要传递一个csrf令牌来提交表单而不确定如何执行此操作。这里有一个类似的答案使用玉:
How to implement CSRF protection in Ajax calls using express.js (looking for complete example)?
然而,我正在使用ejs(使用jsx)(或只是html)并且不想使用jade
答案 0 :(得分:8)
我发现在React中执行此操作的最佳方法是将csrf
标记添加到商店,或将其传递给组件上下文。
您可以通过略微改变Yahoo Fluxible react-router example来了解其完成情况。
context.executeAction(setTokenAction, req.csrfToken(), function(){});
这将使用csrf
标记作为参数执行磁通操作。 Yahoo flux体系结构通过以下方式将商店的值序列化到客户端:
var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';
这会在脚本标记中写入页面,然后可以在客户端javascript中访问该标记。它看起来像这样:
<script>
window.App = {
context: {
dispatcher: {
stores: {
ApplicationStore: {
csrf: "1234abcd",
}
}
}
}
};
</script>
Here is the Html.jsx component in the Flux example.
如果您没有创建同构应用程序(React组件在服务器和客户端上运行),那么我建议只写出包含csrf
令牌的脚本标记。 强>
对于Fluxible,该值为rehydrated on the client。
var dehydratedState = window.App; // Sent from the server
var app = require('./app');
app.rehydrate(dehydratedState, function (err, context) {
...
});
让您在客户端上使用已填充的商店,而无需额外的http请求。然后,您可以通过访问商店从任何地方访问csrf
令牌。
您可以通过上下文传递它:
var componentContext = context.getComponentContext();
componentContext.csrf = req.csrfToken();
...
var markup = React.renderToString(Component({context: componentContext}))
然后,您可以通过组件的道具访问它。
this.props.context.csrf
如果您正在使用Fluxible并希望通过上下文传递它,我可能会在插件中执行此操作,但您明白了。
完整服务器代码:
/**
* Copyright 2014, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
require('babel/register');
var express = require('express');
var favicon = require('serve-favicon');
var serialize = require('serialize-javascript');
var navigateAction = require('./actions/navigate');
var setCsrfTokenAction = require('./actions/setCsrfToken');
var debug = require('debug')('Example');
var React = require('react');
var app = require('./app');
var HtmlComponent = React.createFactory(require('./components/Html.jsx'));
var Router = require('react-router');
var server = express();
server.use(favicon(__dirname + '/../favicon.ico'));
server.use('/public', express.static(__dirname + '/build'));
server.use(function (req, res, next) {
var context = app.createContext();
debug('Executing navigate action');
Router.run(app.getComponent(), req.path, function (Handler, state) {
context.executeAction(setCsrfTokenAction, req.csrfToken(), function(){});
context.executeAction(navigateAction, state, function () {
debug('Exposing context state');
var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';
debug('Rendering Application component into html');
var Component = React.createFactory(Handler);
var html = React.renderToStaticMarkup(HtmlComponent({
state: exposed,
markup: React.renderToString(Component({context:context.getComponentContext()}))
}));
debug('Sending markup');
res.send(html);
});
});
});
var port = process.env.PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
答案 1 :(得分:-3)
将东西通过模板传递到React有点繁琐。简单地为CSRF令牌设置Ajax调用可能更好。
This link详细介绍了如何使用Django和jQuery,但概念应该非常便携。