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

Posted

技术标签:

【中文标题】将 CSRF 令牌从节点传递给 REACT/FLUX【英文标题】:Passing CSRF token to REACT/FLUX from node 【发布时间】:2015-05-13 19:33:34 【问题描述】:

我使用的是 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)并且不想使用玉

【问题讨论】:

呼应 Joel,我真的建议在 React 之外执行此操作。我很喜欢 Angular 的 $http 服务如何通过查找会话 cookie 来处理这个问题,并将其包含在每个传出的 XHR 请求中。 【参考方案1】:

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

您可以通过稍微更改Yahoo Fluxible react-router example 来查看它是如何完成的。

context.executeAction(setTokenAction, req.csrfToken(), function());

这将使用csrf 令牌作为参数执行通量操作。 Yahoo Flux 架构通过以下方式将 store 的值序列化到客户端:

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))

然后你可以通过组件的 props 访问它。

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);

【讨论】:

【参考方案2】:

通过模板将内容传递给 React 有点繁琐。为 CSRF 令牌简单地设置一个 Ajax 调用可能会更好。

This link 详细说明了如何使用 Django 和 jQuery 进行操作,但这些概念应该是非常可移植的。

【讨论】:

以上是关于将 CSRF 令牌从节点传递给 REACT/FLUX的主要内容,如果未能解决你的问题,请参考以下文章

如何将 POST 数据中的 CSRF 令牌传递给 Django?

使用 CSRF_COOKIE_HTTPONLY 将 Django CSRF 令牌传递给 Angular

将 csrf 令牌传递给 blueimp 文件上传

将 csrf 令牌传递给客户端应用程序

如何在 AJAX 中传递 Django csrf 令牌(没有 jQuery)

在 Alamofire 请求参数中传递 CSRF 令牌