Passport-Local не удается авторизовать файл cookie экспресс-сеанса

#node.js #express #passport.js

#node.js #выражать #passport.js

Вопрос:

При вызове незащищенного маршрута я могу распечатать и ответить значениями в req.cookies

 {
    "cookies": {
        "connect.sid": "s:PqWvDsoKLMeCyRd8pGN<removed>",
        "testCookie": "testValue"
    },
    "signedCookies": {}
}
  

Однако этот маршрут возвращает 401 Unauthorized

 router.get('/authCheck', passportWithLocalStrategy.authenticate('local'), (req: Request, res: Response, next: NextFunction) => {
  res.status(204).send();
});
  

Кто-нибудь знает, что может быть причиной того, что файл cookie сеанса не аутентифицируется?

Вот мой основной файл server.ts, удаление / сериализация и стек промежуточного программного обеспечения:

 // called to set a cookie initially
passport.serializeUser((user: any, callback) => {
  callback(null, user.id as string);
});

// called every time a request is made
passport.deserializeUser(async (userId: string, callback) => {
  const pgClient = new PgClient();
  try {
    pgClient.connect();
    const userRecord = (await pgClient.query('SELECT * FROM app_user WHERE CAST(id as text) = CAST($1 as text)', [userId])).rows[0];
    pgClient.end();
    callback(null, userRecord);
  } catch (error) {
    callback(error);
  }
});

server
  .use(cors())
  .use(express.json())
  .use(expressSession({ secret: process.env.SESSION_SECRET! }))
  .use(cookieParser())
  .use(passport.initialize())
  .use(passport.session())
  .use(rootRouter)
  <other routers removed>
  

Я настроил свою Passport LocalStrategy, как показано:

 async function useDatabaseToVerifyUserAndPassword(localUserName: string,
  localPassword: string, doneCallback: any) {
  const pgClient = new PgClient();

  try {
    await pgClient.connect();
    const queryResult = await pgClient.query(selectUserQuery, [localUserName]);
    pgClient.end();
    const userData: UserMatch = queryResult.rows[0];

    if (typeof userData === 'undefined' || typeof userData.password_hash === 'undefined') {
      return doneCallback(null, false);
    }

    const hashesMatch: boolean = await bcrypt.compare(localPassword, userData.password_hash);

    if (hashesMatch) {
      return doneCallback(null, userData);
    }

    return doneCallback(null, false); // username not found or passHash mismatch. Prints 401 UnAuth
  } catch (error) {
    return doneCallback(error, false);
  }
}

const strategyOptions = {
  usernameField: 'localUserName',
  passwordField: 'localPassword',
};

const localStrategy = new LocalStrategy(strategyOptions, useDatabaseToVerifyUserAndPassword);
passport.use(localStrategy);

export default passport;
  

Вышеуказанный экспорт переносится в файл маршрутизатора (для маршрута в /authCheck ) как passportWithLocalStrategy . Если я просто импортирую passport из папки библиотеки в этот файл, маршрут прерывается, зависая на неопределенный срок.

Обновить

Я попытался снять защиту с маршрута и получить доступ req.isAuthenticated() . Он всегда возвращает false, даже если существует файл cookie сеанса.

Я вижу эту информацию, напечатанную при входе в систему req.session

 Session Session {
  cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }  
  

Комментарии:

1. Я бы проверил, что у localUserName и localPassword есть значения. Если вы запрашиваете маршрут без указания имени пользователя и пароля в теле запроса, passport автоматически вернет 401 . Если это сработает, я бы проверил, что пользователь возвращается в вашем запросе к базе данных и что done(null, false) не вызывается.

2. @jasonandmonte да, это работает, когда я предоставляю localUsername и localPassword . Нет ли способа полагаться на файл cookie сеанса сам по себе? Я думал, что смысл сеансов в том, чтобы избежать необходимости указывать имя пользователя и пароль при каждом запросе.

Ответ №1:

У вас должен быть отдельный маршрут входа, который вызывает, passport.authenticate после того, как он успешно вернется, passport добавит req.session.passport значение с сериализованным идентификатором пользователя. Вам нужно выполнить этот процесс только один раз при входе пользователя в систему.

/authCheck Затем маршрут может быть реорганизован с помощью промежуточного программного обеспечения, которое просто проверяет, что пользователь все еще вошел в систему.

 router.get('/authCheck', (req: Request, res: Response, next: NextFunction) => {
  // passport isAuthenticated method
  if(req.isAuthenticated()){
        //req.isAuthenticated() will return true if user is logged in
        return res.status(204).send();
    } else{
        res.redirect("/login");
    }
});
  

Комментарии:

1. Спасибо, я замечаю, что запросы от postman и браузера Chrome req.isAuthenticated() установлены на false , хотя в обоих файлах cookie сеанса присутствуют. Есть идеи, что может быть причиной этого?

2. Интересно. req.session.passport Присутствует в сеансе после входа в систему?