node.js - Passport 不会在浏览器请求中持续存在,可与 Postman 一起使用

Posted

技术标签:

【中文标题】node.js - Passport 不会在浏览器请求中持续存在,可与 Postman 一起使用【英文标题】:node.js - Passport not persisting across browser requests, works with Postman 【发布时间】:2018-02-08 15:42:59 【问题描述】:

我目前正在使用 create-react-app 样板,并一直在尝试添加身份验证。我使用 axios 作为我的基于 Promise 的 HTTP 库和 React.js。我一直在后端使用带有 express、express-session、passport 和 passport-local 的节点。

这是我的 server.js 文件,有一些例外:

const express = require('express');
const mysql = require('mysql');
const app = express();
const cors = require('cors');
const session = require('express-session');
const passport = require('passport');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const LocalStrategy = require('passport-local').Strategy;

// Express only serves static assets in production
if (process.env.NODE_ENV === 'production') 
  app.use(express.static('client/build'));


app.set('port', (process.env.PORT || 3001));

app.use(cors(
  credentials: true,
  origin: 'http://localhost:3000'
));
app.use(morgan('dev'));
app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session(
  secret: 'topsecretpassword',
  resave: true,
  saveUninitialized: false,
  cookie: 
    path: '/',
    originalMaxAge: 1000 * 60 * 60 * 24,
    httpOnly: true,
    secure: false
  
));
app.use(passport.initialize());
app.use(passport.session());


// Setup Database connection
const connection = mysql.createConnection(
  host : 'localhost',
  user : 'root',
  password : '',
  database : 'mvy_db'
);

passport.serializeUser(function(user, done) 
  done(null, user.id);
);

passport.deserializeUser(function(user, done) 
  connection.query('SELECT * FROM users WHERE id=?', user, function(err, userId) 
    if (err) 
      res.status(400).json(
        error: 'Database Error',
        id: userId[0]
      );
    

    done(err, userId[0]);
  );
);

passport.use(new LocalStrategy(
  usernameField: 'email',
  passwordField: 'password',
  ,
  function(email, password, done) 
    connection.query('SELECT * FROM users WHERE email=?', email, function(err, user) 
      if (err) 
        return done(err);
      
      if (!user.length) 
        return done(null, false,  message: 'Incorrect email.' );
      
      if (user[0].password !== password) 
        return done(null, false,  message: 'Incorrect password.' );
      
      return done(null, user[0]);
    );
  
));

app.post('/signin', passport.authenticate('local'), function(req, res) 
  console.log(req.session);
  return res.send('login success!');
);

function isAuthenticated (req,res,next)
  console.log(req.session);
  if(req.session.passport.user)
     return next();
  else
     return res.status(401).json(
       error: 'User not authenticated'
     )



app.get('/checkauth', isAuthenticated, function(req,res) 
  res.status(200).json(
    status: 'User Authenticated!'
  );
)

app.get('/signout', function(req,res) 
  req.session.destroy();
  res.status(200).json( success: 'successfully signed out' );
)

使用邮递员(甚至在浏览器上),我能够成功登录,并且以下内容保存在 req.session 对象中:

   cookie:
     path: '/',
      _expires: null,
      originalMaxAge: 86400000,
      httpOnly: true,
      secure: false ,
      passport:  user: 1  

我使用 axios 的登录请求:

return axios.post(ROOT_URL + 'signin', 
      email: e.target.email.value,
      password: e.target.password.value
    ).then((response) => 
      if (response.status === 200) 
        console.log(response);
      
    )

我使用 axios 的 checkAuth 请求(这是我返回 500 错误的地方):

  axios.get(ROOT_URL + 'checkauth',  withCredentials: true )
    .then((response) => 
      if (response.status === 200) 
        return true;
       else 
        return false;
      
    );

报错前检查身份验证后的req.session对象,注意passport对象不存在了:

 Session 
   cookie:
     path: '/',
      _expires: null,
      originalMaxAge: 86400000,
      httpOnly: true,
      secure: false  

这是我在尝试检查用户是否被授权时在控制台上收到的错误消息:

 TypeError: Cannot read property 'user' of undefined
     at isAuthenticated (/server.js:94:26)

我已经绞尽脑汁好几个小时了,试图解决这个问题。我认为这可能与 CORS 有关,但经过数小时的使用后,情况似乎并非如此。这是一个 CORS 问题仍然是合理的,但真正让我感到困惑的是,它在 Postman 上运行良好,但在我的 Chrome 浏览器上却不行。任何帮助表示赞赏!

【问题讨论】:

【参考方案1】:

好的,所以我找到了解决问题的方法。这似乎是 axios 和我的 get 请求配置的问题。出于某种原因,使用结构 axios.get(URL) .then(response) 不适用于 withCredentials 属性。

相反,我必须将我的请求发送为:

axios(ROOT_URL + 'checkauth', method: 'get', withCredentials: true ) .then((response) => if (response.status === 200) return true; else return false; );

【讨论】:

这对我也有用,仅供参考,我最初使用axios.post 并成功切换到 `axios( method: post...) 。感谢分享!【参考方案2】:

哦,因为我忘记了默认情况下 axious 不发送凭据,所以我不得不坚持使用 jwt 并完全删除会话。

你可以定义一个 axious 的实例,它可以让你更简单地提出请求

const $axios = axios.create(
  baseURL: 'https://some-domain.com/api/',
  withCredentials: true
);

【讨论】:

以上是关于node.js - Passport 不会在浏览器请求中持续存在,可与 Postman 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 passport-auth0 进行 MEAN Stack 用户身份验证,在 Angular 中调用 Node Js passport-auth0 API

如何使用 Passport.js 在 Node.js 中重置/更改密码?

使用 Sails.JS 框架的 Node.JS -- Passport:没有在名称下注册策略:facebook

在带有 React.js 前端的 Node.js 上使用 Passport.js 进行身份验证

Node.js 和 Passport 对象没有方法 validPassword

Express Passport (node.js) 错误处理