Передача токена CSRF в REACT/FLUX с узла

Я использую 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 для отправки формы, и я не знаю, как это сделать. Здесь был аналогичный ответ с использованием нефрита:

Как реализовать CSRF защита в вызовах Ajax с использованием express.js (ищете полный пример)?

Однако я использую ejs (с jsx) (или просто html) и не хочу использовать jade


person Saad    schedule 11.03.2015    source источник
comment
Вторя Джоэлу, я бы действительно предложил сделать это за пределами React. Мне нравится, как служба angular $http обрабатывает это, ища файл cookie сеанса и включая его в каждый исходящий запрос XHR.   -  person Nick Tomlin    schedule 15.03.2015


Ответы (2)


Я обнаружил, что лучший способ сделать это в React — добавить токен csrf в хранилище или передать его в контекст компонента.

Вы можете увидеть, как это делается, слегка изменив пример Yahoo Fluxible react-router.

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

Это выполняет действие потока с токеном csrf в качестве параметра. Архитектура потока Yahoo сериализует значения хранилища для клиента через:

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

Это записывается на страницу в теге сценария, к которому затем можно получить доступ в javascript на стороне клиента. Это будет выглядеть примерно так:

<script>
window.App = {
  context: {
    dispatcher: {
      stores: {
        ApplicationStore: {
          csrf: "1234abcd",
        }
      }
    }
  }
};
</script>

Вот компонент Html.jsx в примере Flux.

Если вы не создаете изоморфное приложение (компоненты React запускаются как на сервере, так и на клиенте), я бы посоветовал просто написать тег скрипта, содержащий токен csrf.

Для Fluxible это значение затем перезагружается на клиенте.

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);
person Joe McBride    schedule 16.03.2015

Передача данных через шаблон в React немного затруднительна. Возможно, было бы лучше просто настроить вызов Ajax для токена CSRF.

По этой ссылке подробно описано, как это сделать с помощью Django и jQuery, но концепции должны быть довольно портативными.

person Joel Auterson    schedule 15.03.2015