我在车把each loop上的CSRF令牌有问题。我用each loop生成了一个数据表,但是我不能提交delete按钮。 CSRF仅适用于提交新数据(POST)和提交更新数据(PUT)。这是我的设置:

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressHbs = require('express-handlebars');
var mongoose = require('mongoose');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var passport = require('passport');
var flash = require('connect-flash');
var validator = require('express-validator');
var override = require('method-override');

var routes = require('./routes/index');
var userRoutes = require('./routes/user');
var itemRoutes = require('./routes/item');

var app = express();


// connect to mongodb
mongoose.Promise = global.Promise;
mongoose.connect('localhost:27017/toolswatcher');
require('./config/passport');

// view engine setup
// app.set('views', path.join(__dirname, 'views'));
app.engine('.hbs', expressHbs({
    defaultLayout: 'layout',
    extname: '.hbs',
    helpers: {
        counter: function(index) {
            return index + 1;
        }
    }
}));
app.set('view engine', 'hbs');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(validator());
app.use(session({
    secret: '234234sda',
    resave: false,
    saveUninitialized: false,
    store: new MongoStore({
        mongooseConnection: mongoose.connection
    }),
    cookie: { maxAge: 100 * 60 * 1000 } // minutes * seconds * milis
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(override(function (req, res) {
    if (req.body && typeof req.body === 'object' && '_method' in req.body) {
        // look in urlencoded POST bodies and delete it
        var method = req.body._method;
        delete req.body._method;
        return method;
    }
}));
app.use(express.static(path.join(__dirname, 'public')));

[...]


路由item.js

    var express = require('express');
    var router = express.Router();
    /*CSRF protection*/
    var csrf = require('csurf');
    var csrfProtection = csrf();
    router.use(csrfProtection);

    var Item = require('../models/item/item');

    /* GET items listing */
    router.get('/', isLoggedIn, function(req, res, next) {
        session_store = req.user.username;
        Item.find({}, function (err, item) {
            if (err) return console.error(err, res);
            res.render('item/index', {items: item, csrfToken: req.csrfToken()});
        }).select('item_id item_name description stock image_path');
    });

    /* Delete item by ID*/
    router.delete('/delete/:id', isLoggedIn, function (req, res, next) {
        Item.findById(req.params.id, function (err, item) {
            item.remove(function (err, item) {
                if(err) return console.error(res, err);
                console.log('DELETE removing ID: ' + item._id);
                res.redirect('/item');
            });
        });
    });


我的看法是:

<h2 class="page-header">Data Items</h2>
<div class="row">
    <div class="col-md-4">
        <a href="/item/add" class="btn btn-primary pull-left">
            <i class="fa fa-plus" aria-hidden="true">&nbsp;New Item</i>
        </a>
    </div>
    <div class="col-md-4 col-md-offset-4">
        <div class="input-group">
            <input type="text" class="form-control" id="searchItem" onkeyup="searchTableItem()" placeholder="Search item name..">
            <div class="input-group-addon"><span><i class="fa fa-search" aria-hidden="true"></i></span></div>
        </div>
    </div>

</div>
<div class="table-responsive no-padding" id="itemList">
        <table class="table table-hover table-striped" id="myTable">
            <thead>
                <th>No.</th>
                <th>Item ID</th>
                <th>Item Name</th>
                <th>Descriptions</th>
                <th>Stock</th>
                <th>Action</th>
            </thead>
            <tbody>
                {{#each items as |item key|}}
                <tr>
                    <td>{{ counter @key }}</td>
                    <td>{{ item.item_id }}</td>
                    <td>{{ item.item_name }}</td>
                    <td>{{ item.description }}</td>
                    <td>{{ item.stock }}</td>
                    <td>
                        <div style="display:inline-block; margin-right:5px;">
                            <a href="/item/details/{{item._id}}" class="btn btn-primary btn-xs">
                                <i class="glyphicon glyphicon-eye-open"></i>
                            </a>
                        </div>
                        <div style="display:inline-block; margin-right:5px;">
                            <a class="btn btn-success btn-xs" href="/item/edit/{{item._id}}">
                                <i class="glyphicon glyphicon-pencil"></i>
                            </a>
                        </div>
                        <div style="display:inline-block; margin-right:5px;">
                            <form action="/item/delete/{{item._id}}" method="post">
                                <input type="hidden" name="_csrf" value="{{ csrfToken }}">
                                <input type="hidden" name="_method" value="DELETE">
                                <button class="btn btn-danger btn-xs" type="submit">
                                    <i class="glyphicon glyphicon-trash"></i>
                                </button>
                            </form>
                        </div>
                    </td>
                </tr>
               {{/each }}
            </tbody>
        </table>
    </div>


我为csrfToken添加了隐藏的输入字段,但它不起作用,每次单击删除按钮时,它始终显示invalid csrf token。我不知道为什么在循环内无法访问令牌,但是如果我在循环外打印csrfToken,它会起作用,令牌会打印在页面上。

最佳答案

您的csrfToken当前正以“”传递。为了解决此问题,而不是{{csrfToken}},请输入{{../csrfToken}}。

答案编辑原因:找到更简单的解决方案。

09-10 11:02