Node.js中的Passport:req.isAuthenticated始终返回false

3

我知道有很多类似的问题,我查看了以前提出的问题,并没有解决我的问题。目前我正在开发一个简单的身份验证 Node.js 应用程序(前端使用 react-native,数据库是 MongoDB)。我正在使用以下软件包:

  • passport-local-mongoose
  • express-session
  • passport-local
  • passport

这是 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;

问题出在这里,经过身份验证后(运作良好),React Native 转到主页,我想获取一些用户登录信息。为此我使用 isLoggedIn 函数,该函数使用 req.isAuthenticated() 并始终返回 false。
我尝试过的最常见答案并没有起作用:
1. 确保 session-passport.init-passport.session 行按正确顺序(我的应用程序中已经是这样)。
2. 与问题相关的客户端 get-post 调用(在我的 React Native 应用程序中 -> axios.post(BaseURL+url,data,{ withCredentials: true }),也在服务器应用程序中 -> var corsOptions = {origin: '*',credentials: true};app.use(cors(corsOptions)))。
3. 有人说如果你正在使用 https 协议,你必须设置 {secure:true} (但我没有)。
4. 有人说“身份验证后,passport.js 要求您重新路由/重定向,否则会话不会创建,但很多人也遇到重定向问题。我尝试过它没有解决问题。
5. 有一个人说不要使用 express-session,使用 client-sessions(我尝试过了,没有作用)。
6. 有些人建议更改序列化和反序列化函数(我尝试过网上找到的其他代码,但都没有起作用),但问题是我的反序列化函数从未运行(我认为该函数在 isAuthenticated() 之后运行,并检查 req 上的用户信息,但我的 req 没有那些信息。基本上,我可以登录到应用程序,但它不会在请求中保存我的会话)。
7. 有一个人建议说,“ express-session 尝试延迟重定向,但有些浏览器在重定向之前不等待整个响应。因此,您需要在重定向之前手动保存。”这解决了几乎所有人的问题,但没有解决我的问题。(如您所见,在我的代码中 req.session.save(() => res.send("Başarılı"));)
8. 另外,还有一个人说延迟也可以解决问题(我尝试过了,但没有作用)。
如果有人除了这些之外有其他解决方案,请分享。我接受所有建议。

你最终解决了这个问题吗? - VericalId
1个回答

0

我通过稍微更改服务器代码来解决了这个问题。自从上次我与这个项目相关的工作以来,我不得不休息一下,所以有些部分我不太记得为什么要更改,但是最终代码可以运行。

我认为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提供的默认代码,但它们并没有起作用。所以我开始先稍微更改session。为此,我需要导入一个库来创建随机会话ID(uuid),同时我也开始从服务器端保存会话到文件中。我想我不必导入任何库来保存数据,我可以将所有信息保存在数据库中,但我更喜欢继续使用session-file-store库。我还将passport-local库添加到了这个文件中(之前只在用户模型上使用过)。最后,我不得不添加body-parser库来解析响应。我必须指出,我之前使用express.urlencoded()函数,并且对我的路由工作得很好。我不必使用另一个库来解析请求正文。据我记得,当我为会话添加一些中间件时,这个express.urlencoded就不起作用了,于是我尝试了其他的方法,在我的代码中加入了body-parser库,结果它就正常工作了。
app.use(bodyParser.urlencoded({ extended: false })); 
app.use(express.urlencoded({ extended: false }))

我不知道这两行代码之间的确切区别。但我知道它们的工作方式不同,而且似乎 body-parser 库比 express parser 更好。

我更改了我的会话设置

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,并将其保存到请求中。这段代码在我的路由器之前运行,因此每个请求都有一个sessionId。我认为express-session会检查请求是否具有sessionId并且是否已保存到服务器端,然后才调用genId函数,这意味着仅当请求没有会话ID或会话ID未存储在服务器中时才调用该函数。浏览器保存您的会话ID并对每个请求使用相同的ID。在服务器上保存的会话作为对象保存会话的cookie信息。Passport.js将您的userId或用户名放入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时序列化仅用户ID(至少在确保程序的其他部分没有错误之前不要这样做)。我曾经在使用findById进行deserializeUser时遇到了一些问题(我的问题与使用MongoDB自动创建的默认对象ID有关)。它没有给出任何错误,但返回500作为响应。
SerializeUser在登录后调用并将您的信息放入cookie中。如果您的请求具有保存在服务器端的cookie,则会调用DeserializeUser。 在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!\n');
    });
  })(req, res, next);
});

我已经修改了我的登录函数。所以当你稍微更改一下会话设置时,它实际上运行得很好。我甚至删除了session.save()部分,因为会话甚至在之前就已经创建了。我的问题是会话数据没有保存为对象在会话中,所以我试图强制保存它。

所有这些更改后,服务器端工作正常。我用Postman测试了这段代码,它完美地工作了。然而,尽管我向浏览器发送了一个cookie,但浏览器并没有保存我的cookie。这与前端或浏览器有关的问题。然而,这个服务器端的问题已经解决了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接