在过去的几个小时中,我一直未能成功在Google上找到以下问题的解决方案:
我设置了csurf,并且运行良好。它适用于与注册/登录用户相关的POST请求。我正在尝试在用户个人资料中创建一个表单,以更新用户的数据,但是当我点击“提交”时,我得到了ForbiddenError: invalid csrf token
。
在进一步测试中,csrt令牌是在个人资料页面上创建的,但是由于某种原因,它是无效的。
(我最近才开始学习编程,如果错过了一些内容,我愿意提供其他信息。)
使用的工具:
我的app.js
let express = require("express"),
app = express(),
bodyParser = require("body-parser"),
cookieParser = require('cookie-parser'),
session = require("express-session"),
mongoose = require("mongoose"),
passport = require("passport"),
flash = require('connect-flash'),
validator = require('express-validator'),
LocalStrategy = require("passport-local"),
csrf = require('csurf'),
csrfProtection = csrf({ cookie: true }),
MongoStore = require('connect-mongo')(session);
let indexRoutes = require('./routes/index');
let userRoutes = require('./routes/user');
let User = require("./models/user");
// APP CONFIGURATION
mongoose.connect("mongodb://localhost:27017/azax", { useNewUrlParser: true, useUnifiedTopology: true, }).then(() => {
console.log("Connected to MongoDB");
}).catch((error) => {
console.log("Something is wrong...");
});
require('./config/passport');
// View engine setup
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/public"));
// Initial setup
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(validator());
// Session setup
app.use(cookieParser());
app.use(session({
secret: 'somesecretforbytox',
resave: false,
saveUninitialized: false
}));
app.use(flash());
// Initialize passport
app.use(passport.initialize());
app.use(passport.session());
app.use(csrf());
// CSRF
app.use(function (req, res, next) {
var token = req.csrfToken();
res.cookie('XSRF-TOKEN', token);
res.locals.csrfToken = token;
next();
});
app.use(function (req, res, next) {
res.locals.currentUser = req.user;
res.locals.session = req.session;
next();
});
// ======================
// Connect to route files
// ======================
app.use('/user', userRoutes);
app.use(indexRoutes);
app.listen(3033, function () {
console.log("Listening at port 3033...");
});
我的password.js:
let passport = require('passport');
let User = require('../models/user');
let LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function (req, email, password, done) {
req.checkBody('username', 'Invalid username').notEmpty();
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
let errors = req.validationErrors();
if (errors) {
let messages = [];
errors.forEach(function (error) {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({ 'email': email }, function (err, user) {
if (err) {
return done(err);
}
if (user) {
return done(null, false, { message: 'Вече има акаунт с този имейл.' })
}
let username = req.body.username;
let newUser = new User();
newUser.username = username;
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.country = 'България';
newUser.save(function (err, result) {
if (err) {
return done(err);
}
return done(null, newUser);
});
});
}));
passport.use('local-signin', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function (req, email, password, done) {
// req.checkBody('username', 'Invalid username').notEmpty();
req.checkBody('email', 'Invalid email').notEmpty();
req.checkBody('password', 'Invalid password').notEmpty();
let errors = req.validationErrors();
if (errors) {
let messages = [];
errors.forEach(function (error) {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({ 'email': email }, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: 'Акаунтът не е намерен.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Грешна парола.' });
}
return done(null, user);
});
}));
HTML ...:
<form action="/user/profile" method="POST" class="form-validate form-horizontal" enctype="multipart/form-data">
<fieldset>
<legend>Edit address</legend>
<!-- email -->
<div class="control-group">
<div class="control-label">
<label id="jform_email1-lbl" for="jform_email" class="hasPopover required" title="" data-content="Enter new email address." data-original-title="Email Address">
Email<span class="star"> *</span></label>
</div>
<div class="controls">
<input type="email" name="email" class="validate-email required" id="jform_email" value="<%= (typeof currentUser.email != 'undefined' ? currentUser.email : '') %>" size="30" autocomplete="email" required aria-required="true">
</div>
</div>
<!-- name -->
<div class="control-group">
<div class="control-label">
<label id="jform_fname-lbl" for="jform_fname" class="hasPopover required" title="" data-content="Enter new name." data-original-title="Name">
Name<span class="star"> *</span></label>
</div>
<div class="controls">
<input type="text" name="firstName" id="jform_fname" value="<%= (typeof currentUser.firstName != 'undefined' ? currentUser.firstName : '') %>" class="required" size="30" required aria-required="true">
</div>
</div>
</fieldset>
<div class="form-actions">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button type="submit" class="btn btn-primary validate">
<span>Save</span>
</button>
<a class="btn" href="/" title="Cancel">Cancel</a>
</div>
</form>
user.js:
let express = require('express'),
router = express.Router(),
csrf = require('csurf'),
csrfProtection = csrf(),
passport = require('passport');
router.use(csrfProtection);
let User = require("../models/user");
// user profile
router.get("/profile", isLoggedIn, csrfProtection, function (req, res) {
res.render("user/profile", { csrfToken: req.csrfToken(), currentUser: req.user });
});
router.post('/profile', (req, res) => {
updateRecord(req, res);
res.redirect('/profile');
});
// update user data
function updateRecord(req, res) {
User.findOne({ _id: req.user.id }, (err, doc) => {
doc.name = req.body.name;
doc.save(function (err, doc) {
});
});
}
router.get("/profile/edit", isLoggedIn, csrfProtection, function (req, res) {
res.render("user/edit", { csrfToken: req.csrfToken(), currentUser: req.user });
});
// sign up form works with csrf
// signup form
router.get("/signup", csrfProtection, function (req, res) {
let messages = req.flash('error');
res.render("user/signup", { csrfToken: req.csrfToken(), messages: messages, hasErrors: messages.length > 0 });
});
// ... more routes
module.exports = router;
// middleware
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/user/login');
}
答案 0 :(得分:0)
对我有用的是将以下隐藏字段添加到每种表单中:
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
并将令牌发送到显示表单的模板页面的每个获取请求。
{csrfToken: req.csrfToken()}
喜欢
router.get('/user/login',function(req,res){
res.render('pages/login', {csrfToken: req.csrfToken()});
})
这修复了整个应用程序中的错误。