问题描述
我知道有很多类似的问题,我检查了之前提出的问题,没有一个答案能解决我的问题。我目前正在开发一个简单的身份验证node.js应用程序(前端是原生的,数据库是MongoDB)。为此,我使用以下软件包:
- Passport-Local-Mongoose
- Express-Session
- 护照-本地
- 护照
这里是app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var passport = require('passport');
var user = require('./models/user');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var cookieParser = require('cookie-parser')
var app = express();
app.use(cookieParser('keyboard cat'));
var corsOptions = {
origin: '*',
credentials: true };
app.use(cors(corsOptions))
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//auth settings
app.use(require("express-session")({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(user.createStrategy());
passport.serializeUser(user.serializeUser());
passport.deserializeUser(user.deserializeUser());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// 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;
以下是用户模型:
var mongoose=require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');
var userShema = new mongoose.Schema({
username : String,
password : String
})
userShema.plugin(passportLocalMongoose);
var user= mongoose.model("User",userShema);
module.exports = user;
这是我的路由文件
var express = require('express');
var router = express.Router();
var user= require("../models/user");
const passport = require('passport');
var isLoggedIn =require('../session');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/login', function(req, res, next) {
passport.authenticate('local' ,function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.send("-1"); }
req.logIn(user, function(err) {
if (err) { return next(err); }
req.session.save(() => res.send("Başarılı"));
});
})(req, res, next);
});
router.post('/signUp', async function(req, res, next) {
try{
console.log('registering user');
user.register(new user({username: req.body.username}), req.body.password, function(err) {
if (err) {
console.log('error while user register!', err);
return next(err);
}
console.log('user registered!');
res.redirect('/');
});
}
catch(e){
console.log(e);
res.status(503).send("-1")
}
});
router.get('/logOut', function(req,res,next){
req.logOut();
res.send("1");
})
router.get('/home',isLoggedIn,function(req,res,next){
res.send("Success");
})
module.exports = router;
最后是session.js
const passport = require('passport');
var isLoggedIn =(req,res,next) =>{
if(req.isAuthenticated()){
return next();
}
res.status(403).send("Something went wrong")
}
module.exports = isLoggedIn;
这里的问题是,在身份验证(该方法工作正常)之后,原生Reaction转到主页,我希望在用户登录时获取一些信息。为此,我使用isLoggedIn函数,该函数使用req.isAuthenticated()并返回始终为false。
我尝试过但不起作用的最常见答案是
- 确保session-passport.init-passport.session行顺序正确(已在我的应用程序中)
- 发出相关客户端GET-POST调用(在我的REACT-NATIVE app->;axios.post(BaseURL+url,data,{with Credentials:true})中),也在服务器app->;var corsOptions={ 来源:‘*’, 凭证:true}; app.use(CORS(CorsOptions))
- 有人说如果您使用https,则必须设置{Secure:true}(我没有设置)
- 有人说&q;认证后,passport.js要求您重新路由/重定向&q;,否则不会创建会话,但是很多人在重定向方面也有问题。我确实试过了,但没有解决问题。
- 有人说不要使用Express-Session,使用Client-Session(我试过了,没有用) 有人建议更改序列化和反序列化函数(我尝试了在Internet上找到其他代码,但都不起作用),但问题是我的反序列化函数从未运行过(我认为此函数在isAuthenticated()之后工作,并检查请求的用户信息,但我的请求没有该信息。基本上,我可以登录到该应用程序,但它不会在请求中保存我的会话。)
- 有人建议";express-session尝试延迟重定向,但有些浏览器在定向之前并不等待整个响应。所以在重定向之前你需要手动保存。它解决了几乎所有人的问题,除了我。(在我的代码中,您可以看到req.session.save(()=>;res.send(";Başarılı";);)
- 另外,另一个人说延迟也可以解决这个问题(我试过了,但是没有)
因此,如果任何人在这些解决方案之外还有其他解决方案,请与我们分享。我愿意接受所有建议。
推荐答案
我稍微更改了一下服务器代码就解决了这个问题。自从上次从事与此项目相关的工作以来,我不得不休息一下,所以有些部分我不太记得为什么要更改,但是,在一天结束时,代码可以正常工作。
我认为Express-Session和Passport之间有问题,因此在req.session中创建了会话,但没有Passport对象。
在App.js中,我必须添加一些新库:
const { v4: uuidv4 } = require('uuid');
const FileStore = require('session-file-store')(session);
const LocalStrategy = require('passport-local').Strategy;
const bodyParser = require("body-parser");
我以前使用过Express-Session和Passport提供的一些默认代码,它们不起作用。所以我开始先稍微改变一下课程。为此,我需要导入库以创建随机会话id(Uuid),还启动了以从服务器端将会话保存在文件中。我想我不必导入任何库来保存数据,我可以保存数据库中的所有信息,但我更喜欢使用会话文件存储库。我还将Passport-local库添加到此文件中(它以前只在用户模型上使用过)。最后,我必须添加主体解析器库来解析响应。我必须指出我以前使用的是expression s.urlencode()函数,它对我的路由工作得很好。我不必使用另一个库来解析请求正文。就我所记得的,当我为会话添加一些中间件时,这个表达式.urlencode不起作用,我想让我们尝试另一个,并将正文解析器库放入我的代码中,它工作得很好。
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.urlencoded({ extended: false }))
我不知道这两行之间的确切区别。但我知道它们的工作方式不同,主体解析器库似乎比表达式解析器工作得更好。
我更改了会话的设置
app.use(session({
genid: (req) => {
console.log('Inside the session middleware')
console.log(req.sessionID)
return uuidv4(); // use UUIDs for session IDs
},
store: new FileStore(),
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
因此,基本上我使用Session对象创建id,并将其保存为request。此代码在我的路由器之前运行,因此每个请求都有一个sessionId。我认为express-session会在调用genID函数之前检查请求是否有sessionId,以及它是否保存到服务器端,这意味着只有当请求没有session-id或者会话id没有存储在服务器中时才会调用该函数。
浏览器保存您的会话ID,并对每个请求使用相同的ID。作为对象保存在服务器中的会话保存会话的Cookie信息。Passport.js
将您的用户ID或用户名放入Cookie(当然,如果您已登录),以便我们可以区分该Cookie是否与帐户相关。
我使用的是来自Passport-local的默认策略方法,但我重写了它。LocalStrategy函数是当请求发送到‘./login’时执行身份验证的位置。在LOGIN(POST)函数中,您可以使用passport.Authenticate(‘local’,function(err,user,info){}->;这里local表示使用您在app.js
中决定的本地策略passport.use(new LocalStrategy(
function(username, password, done) {
console.log("passport localStrategy",username,password)
user.findOne({ username: username }, function (err, user) {
user.authenticate(password).then(res => {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!res.user) { return done(null, false); }
console.log('Local strategy works fine')
return done(null, user);
})
});
}
));
//takes user and save it to session file store
//saves the user id in the request object as request.session.passport
//and adds request object as request.user.
passport.serializeUser(function(user, done) {
console.log('Inside serializeUser callback. User id is save to the session file store here')
done(null, user);
});
passport.deserializeUser(function(user, done) {
console.log('Inside De-serializeUser callback.')
done(null,user)
});
如果您正在使用MongoDB,我建议您不要序列化惟一的user.id(至少在您确定程序的其他部分可以正常工作之前不要这样做)。我在使用findById函数的desializeUser时遇到了一些问题(我的问题与使用MongoDB自动创建的默认objectID有关)。它没有给出任何错误,但作为响应返回到500。
SerializeUser在登录后被调用,并将您的信息放入cookie中。如果您的请求具有保存在服务器端的Cookie,则调用Anti ializeUser。
在Index.js(我的路由器文件)
router.post('/login', function(req, res, next) {
console.log("inside of the login",req.sessionID)
//passport.authenticate with local parameter will call function that configured in passport.use(new strategyCalss)
passport.authenticate('local' ,function(err, user, info) {
console.log('Inside passport.authenticate() callback');
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
if (err) { return next(err); }
if (!user) { return res.send("-1"); }
//req.login calls passport.serialize user
req.login(user, function(err) {
console.log('Inside req.login() callback')
console.log(`req.session.passport: ${JSON.stringify(req.session.passport)}`)
console.log(`req.user: ${JSON.stringify(req.user)}`)
if (err) { return next(err); }
return res.send('You were authenticated & logged in!
');
});
})(req, res, next);
});
我按如下方式更改了我的登录函数。因此,当您稍微更改会话设置时,它实际上工作得很好。我甚至删除了session.save()部分,因为会话甚至是以前创建的。我的问题是会话数据没有保存为会话中的对象,所以我尝试强制保存它。
完成所有这些更改后,服务器端工作正常。我和邮递员一起测试了这段代码,它工作得很好。但是,即使我向浏览器发送了cookie,浏览器也没有保存我的cookie。与前端或浏览器相关的问题。但是,服务器端的此问题已解决。
这篇关于节点js Passport的req.isAuthenticated返回始终为false的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!