I get "ForbiddenError: invalid csrf token" when I try to use {cookie: { secure: true }} session configuration. How do I implement this?
I get "ForbiddenError: invalid csrf token" when I try to use {cookie: { secure: true }} session configuration. How do I implement this?
我不明白为什么这不起作用。我在单击登录时收到此“ForbiddenError:无效的 csrf 令牌”消息,但我读到必须在会话中启用 {cookie: {httpOnly: true, secure: true}}
选项才能获得相对安全的应用程序 运行(我使用JWT,我是会话和 cookie 方面的新手)
这是我的文件:
app.js
// ____ Imports ____
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const sessionConfig = require('./middleware/sessions');
const userProvider = require('./middleware/userProvider');
const connectDB = require('./services/db');
const csrf = require('csurf');
// ____ Middlewares ____
const app = express();
const csrfProtection = csrf();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(sessionConfig);
app.use(userProvider);
app.use(csrfProtection);
app.use((req, res, next) => {
res.locals.isAuth = req.session.isAuth;
res.locals.csrfToken = req.csrfToken();
next();
});
// ____ Routes ____
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
const errorController = require('./controllers/error');
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.use(errorController.get404);
// ____ Database & Server spin-up ____
const PORT = process.env.PORT || 3000; //deployment looks for process.env.PORT
connectDB(() => {
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
});
./middleware/sessions.js
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const config = require('config');
const store = new MongoDBStore({
uri: config.get('mongoURI'),
collection: 'sessions',
});
const sessionConfig = session({
secret: config.get('sessionSecret'),
resave: false,
saveUninitialized: false,
store: store,
cookie: { httpOnly: true, secure: true },
});
module.exports = sessionConfig;
./middleware/isAuth.js
module.exports = (req, res, next) => {
if (!req.session.isAuth) {
return res.redirect('/login');
}
next();
};
./middleware/userProvider.js
const User = require('../models/user');
module.exports = async (req, res, next) => {
try {
if (!req.session.user) {
return next();
}
let user = await User.findById(req.session.user._id);
req.user = user;
next();
} catch (error) {
console.log(error);
}
};
postLogin控制器(通过isAuth中间件)
exports.postLogin = async (req, res) => {
try {
let { email, password } = req.body;
let user = await User.findOne({ email: email });
let doMatch = await bcrypt.compare(password, user.password);
if (doMatch) {
console.log('Match!');
//use .save() method to make sure it redirects only when session is already created
req.session.user = user;
req.session.isAuth = true;
return req.session.save(() => {
res.redirect('/');
});
} else {
return res.redirect('/login');
}
} catch (error) {
console.log(error);
}
};
./views/auth/login.ejs
<%- include('../includes/head.ejs') %>
<link rel="stylesheet" href="/css/forms.css">
<link rel="stylesheet" href="/css/auth.css">
</head>
<body>
<%- include('../includes/navigation.ejs') %>
<main>
<form class="login-form" action="/login" method="POST">
<div class="form-control">
<label for="email">E-Mail</label>
<input type="email" name="email" id="email">
</div>
<div class="form-control">
<label for="password">Password</label>
<input type="password" name="password" id="password">
</div>
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn" type="submit">Login</button>
</form>
</main>
<%- include('../includes/end.ejs') %>
确实在 mongoDB 中创建了会话,但未定义用户或 isAuth(在下面的文档中显示为 isLoggedin)。
在缩小到 secure: true
问题之后(当我第一次询问时我不知道是什么导致了这种行为),我发现这个线程解释了 http 服务器没有得到 secure: true
cookie ()
在 localhost 中,我使用 http,所以这当然行不通。当我把它放在生产环境中时它起作用了:)
我不明白为什么这不起作用。我在单击登录时收到此“ForbiddenError:无效的 csrf 令牌”消息,但我读到必须在会话中启用 {cookie: {httpOnly: true, secure: true}}
选项才能获得相对安全的应用程序 运行(我使用JWT,我是会话和 cookie 方面的新手)
这是我的文件:
app.js
// ____ Imports ____
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const sessionConfig = require('./middleware/sessions');
const userProvider = require('./middleware/userProvider');
const connectDB = require('./services/db');
const csrf = require('csurf');
// ____ Middlewares ____
const app = express();
const csrfProtection = csrf();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(sessionConfig);
app.use(userProvider);
app.use(csrfProtection);
app.use((req, res, next) => {
res.locals.isAuth = req.session.isAuth;
res.locals.csrfToken = req.csrfToken();
next();
});
// ____ Routes ____
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
const errorController = require('./controllers/error');
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.use(errorController.get404);
// ____ Database & Server spin-up ____
const PORT = process.env.PORT || 3000; //deployment looks for process.env.PORT
connectDB(() => {
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
});
./middleware/sessions.js
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const config = require('config');
const store = new MongoDBStore({
uri: config.get('mongoURI'),
collection: 'sessions',
});
const sessionConfig = session({
secret: config.get('sessionSecret'),
resave: false,
saveUninitialized: false,
store: store,
cookie: { httpOnly: true, secure: true },
});
module.exports = sessionConfig;
./middleware/isAuth.js
module.exports = (req, res, next) => {
if (!req.session.isAuth) {
return res.redirect('/login');
}
next();
};
./middleware/userProvider.js
const User = require('../models/user');
module.exports = async (req, res, next) => {
try {
if (!req.session.user) {
return next();
}
let user = await User.findById(req.session.user._id);
req.user = user;
next();
} catch (error) {
console.log(error);
}
};
postLogin控制器(通过isAuth中间件)
exports.postLogin = async (req, res) => {
try {
let { email, password } = req.body;
let user = await User.findOne({ email: email });
let doMatch = await bcrypt.compare(password, user.password);
if (doMatch) {
console.log('Match!');
//use .save() method to make sure it redirects only when session is already created
req.session.user = user;
req.session.isAuth = true;
return req.session.save(() => {
res.redirect('/');
});
} else {
return res.redirect('/login');
}
} catch (error) {
console.log(error);
}
};
./views/auth/login.ejs
<%- include('../includes/head.ejs') %>
<link rel="stylesheet" href="/css/forms.css">
<link rel="stylesheet" href="/css/auth.css">
</head>
<body>
<%- include('../includes/navigation.ejs') %>
<main>
<form class="login-form" action="/login" method="POST">
<div class="form-control">
<label for="email">E-Mail</label>
<input type="email" name="email" id="email">
</div>
<div class="form-control">
<label for="password">Password</label>
<input type="password" name="password" id="password">
</div>
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn" type="submit">Login</button>
</form>
</main>
<%- include('../includes/end.ejs') %>
确实在 mongoDB 中创建了会话,但未定义用户或 isAuth(在下面的文档中显示为 isLoggedin)。
在缩小到 secure: true
问题之后(当我第一次询问时我不知道是什么导致了这种行为),我发现这个线程解释了 http 服务器没有得到 secure: true
cookie (
在 localhost 中,我使用 http,所以这当然行不通。当我把它放在生产环境中时它起作用了:)