将CSRF令牌从节点传递到REACT/FLUX

Saa*_*aad 9 flux reactjs reactjs-flux

我正在使用nodejs并且通常传递csrf令牌,如下所示:

util.js中

module.exports.csrf = function csrf(req, res, next){
     res.locals.token = req.csrfToken();
     next();
??};
Run Code Online (Sandbox Code Playgroud)

app.js

app.use(csrf());
app.use(util.csrf);
Run Code Online (Sandbox Code Playgroud)

然后在ejs页面我会这样做

<input type="hidden" name="_csrf" value="<%= token %>">
Run Code Online (Sandbox Code Playgroud)

但是,现在我正在使用flux/react作为我的前端,需要传递一个csrf令牌来提交表单而不确定如何执行此操作.这里有一个类似的答案使用玉:

如何使用express.js在Ajax调用中实现CSRF保护(寻找完整示例)?

但是,我正在使用ejs(使用jsx)(或只是html)并且不想使用jade

Joe*_*ide 8

我发现在React中执行此操作的最佳方法是将csrf令牌添加到商店,或将其传递给组件上下文.

您可以通过稍微改变Yahoo Fluxible react-router示例来了解它是如何完成的.

context.executeAction(setTokenAction, req.csrfToken(), function(){});
Run Code Online (Sandbox Code Playgroud)

这将以csrf令牌作为参数执行磁通动作.Yahoo flux体系结构通过以下方式将商店的值序列化到客户端:

var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

这将被写入脚本标记中的页面,然后可以在客户端javascript中访问该标记.它看起来像这样:

<script>
window.App = {
? context: {
? ? dispatcher: {
? ? ? stores: {
? ? ? ? ApplicationStore: {
? ? ? ? ? csrf: "1234abcd",
? ? ? ? }
? ? ? }
? ? }
? }
};
</script>
Run Code Online (Sandbox Code Playgroud)

这是Flux示例中的Html.jsx组件.

如果您没有创建同构应用程序(React组件在服务器和客户端上运行),那么我建议只写出包含csrf令牌的脚本标记.

对于Fluxible,该值然后在客户端上重新水合.

var dehydratedState = window.App; // Sent from the server
var app = require('./app');

app.rehydrate(dehydratedState, function (err, context) {
  ...
});
Run Code Online (Sandbox Code Playgroud)

让您在客户端上使用已填充的商店,而无需额外的http请求.然后,您可以csrf通过访问商店从任何地方访问令牌.

你可以通过这样的方式通过上下文传递它:

var componentContext = context.getComponentContext();
componentContext.csrf = req.csrfToken();

...

var markup = React.renderToString(Component({context: componentContext}))
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过组件的道具访问它.

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);
Run Code Online (Sandbox Code Playgroud)


Joe*_*son -3

通过模板将内容传递到 React 有点繁琐。最好简单地为 CSRF 令牌设置 Ajax 调用。

此链接详细介绍了如何使用 Django 和 jQuery 来实现这一点,但这些概念应该非常易于移植。