昨天,我尝试使用Node.js和框架Express.js创建一个网站。在此网站上,用户需要使用凭据登录数据库中的人员。如果凭据正确,我想在会话中保存用户的信息。
在这个目标中,我使用中间件Express-Session,但是我遇到了问题。当用户键入好的凭据时,其信息会正确存储在会话中。但是,在将用户重定向到主页后,会话被清除,因此存储用户信息的变量现在是未定义的。
我尝试了很多解决方案,并且我搜索了很多,但是我没有找到解决这个问题的方法......
有我的代码: app.js:
const createError = require('http-errors');
const express = require('express');
const session = require('express-session');
const path = require('path');
const helmet = require('helmet');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const bodyParser = require('body-parser');
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const admRouter = require('./routes/adm');
const urlencodedParser = bodyParser.urlencoded({extended : false});
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(urlencodedParser);
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({secret: 'secret', resave: false, saveUninitialized: false, cookie: { maxAge : 60000, secure: false }}));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/adm', admRouter);
// On utilise helmet pour sécuriser l'application.
app.use(helmet());
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
app.listen(80);
和index.js:
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const verif = require('../functions/verif');
const password = require('node-php-password');
const dbServer = require('../database');
// const credentials = require('../functions/dbCredentials');
// const dbServer = mysql.createConnection(credentials);
const urlencodedParser = bodyParser.urlencoded({extended : false});
/* GET home page. */
router.get('/', function(req, res, next) {
console.log(JSON.stringify(req.session.user));
res.render('index', {verif, req });
});
router.post('/login', urlencodedParser, (req, res, next) => {
if(req.body.username !== undefined && req.body.password !== undefined) {
if(req.body.username !== null && req.body.password !== null) {
dbServer.query('SELECT * FROM users WHERE username = ?', [req.body.username], function(error, result, fields) {
if (error) throw error;
// if(password.verify(req.body.password, result))
console.log("resultat : " + JSON.stringify(result));
if(result.length > 0) {
const utilisateur = result[0]; // On stocke la ligne concernant l'utilisateur dans une constante locale.
console.log("L'utilisateur existe.");
// On teste le résultat obtenu, pour savoir si son mot de passe est correct.
if(password.verify(req.body.password, utilisateur.password)) {
console.log("Mot de passe correct.");
req.session.user = utilisateur;
console.log(req.session.user);
} else {
// TODO : Session, pour afficher l'erreur.
console.log("Mot de passe incorrect.");
}
}
else {
console.log("L'utilisateur n'existe pas.")
// TODO : Session, pour afficher l'erreur.
}
});
}
}
res.redirect('/');
});
module.exports = router;
使用此代码,当用户登录时,使用:
console.log(req.session.user);
显示正确的信息,但行:
console.log(JSON.stringify(req.session.user));
路线'/'的显示“未定义”。
所以,在这种情况下我有点失落...... 你有解决这个问题的想法吗? 谢谢advance =)
答案 0 :(得分:1)
问题是,你过早地重定向它们。数据库查询比服务器中运行的大多数代码花费的时间更长,这就是使用回调和承诺的原因。我会在数据库查询结束时移动var choices = $('input[name="choices"]')
var checkedChoices = ???
。在最后一个else语句之后。这应该修复它,因为它允许在重定向之前运行所有内容。
答案 1 :(得分:0)
您正在为express-session
使用内存中的隐式存储。他们建议不要在生产中使用它,但是我的经验是,即使在简单的开发环境中,它也绝对不稳定。我尝试在超时setTimeout(() => res.redirect('/'), 1000)
中进行重定向,从统计上讲,它失败的次数少于直接调用它的次数,尽管这很理想。
在我目前的情况下,我最终实现了自己的哑存储器存储,只是为了将事情向前推进,随后将切换到数据库后端。
最新编辑:我进行了一些广泛的测试,就我而言,似乎在设置会话Cookie和重定向之间可能存在一些竞争条件,我认为有时浏览器会在设置之前进行重定向SID的东西。通过在执行操作的每一步记录活动会话,我设法找到了答案,而且似乎没有明显的原因在重定向上创建了新会话。
答案 2 :(得分:0)
我遇到过这个问题,并通过 express-session 自述文件给出的提示解决了。
如果您查看 readme.md 的 https://github.com/expressjs/session#cookiesecure 部分,您会注意到以下声明:
<块引用>请注意,secure: true 是推荐选项。但是,它需要启用 https 的网站,即安全 cookie 需要 HTTPS。 如果设置了安全,并且您通过 HTTP 访问您的网站,则不会设置 cookie。
因此,我尝试了以下操作:
const sess = {
secret: 'My app',
store: MongoStore.create({
mongoUrl: 'mongodb://localhost:27017/myBaseApp',
crypto: {
secret: 'My database'
}
}),
resave: true,
saveUninitialized: false,
cookie: {
secure: false, //setting this false for http connections
maxAge: 3600000,
expires: new Date(Date.now() + 3600000)
}
}
并且重定向开始正常工作。
答案 3 :(得分:0)
几乎所有具有回调的东西都是异步的,这需要您的脚本在发送信息/继续其他可能创建所谓的竞争条件的行为之前等待回复。
正如其他答案所建议的,这是一个如何在成功/失败时重定向的示例:
"bannedWords": [
"f word",
"s word"
]
为了更好地理解,某些包具有更好的 router.post('/login', urlencodedParser, (req, res) => {
// only in some cases
let sendRedirectDirectly = true;
if(req.body.username !== undefined && req.body.password !== undefined) {
if(req.body.username !== null && req.body.password !== null) {
// here you need to wait for the result of the query
sendRedirectDirectly = false;
dbServer.query('SELECT * FROM users WHERE username = ?', [req.body.username], function(error, result, fields) {
if (error) throw error;
// if(password.verify(req.body.password, result))
console.log("resultat : " + JSON.stringify(result));
if(result.length > 0) {
const utilisateur = result[0]; // On stocke la ligne concernant l'utilisateur dans une constante locale.
console.log("L'utilisateur existe.");
// On teste le résultat obtenu, pour savoir si son mot de passe est correct.
if(password.verify(req.body.password, utilisateur.password)) {
console.log("Mot de passe correct.");
req.session.user = utilisateur;
console.log(req.session.user);
// now we need to call next() or forward the user again
res.redirect('/?loginSuccess');
} else {
// TODO : Session, pour afficher l'erreur.
console.log("Mot de passe incorrect.");
// if password is incorrect
res.redirect('/?incorrectPass');
}
}
else {
console.log("L'utilisateur n'existe pas.")
// TODO : Session, pour afficher l'erreur.
// if username not found:
res.redirect('/?incorrectCredentials');
}
});
}
}
// as noted above
if (sendRedirectDirectly)
res.redirect('/');
});
支持,并允许编写如下例所示的代码。 (例如 mssql 包)
async
/await
函数/语句会暂停脚本的执行,直到满足 Promise
you async
并抛出可由 try/catch-block 处理的可捕获错误。>
如果一个函数用 await
声明,它总是返回一个 Promise
。
你也可以将 mysql-query 包装成一个 Promise:
async
现在您可以使用:
function mysqlQuery(...args) {
return new Promise((resolve, reject) => {
dbServer.query(...args, (error, result, fields) => {
if (error)
return reject(error);
resolve([result, fields]);
})
})
}