Сессия не правильно получена из хранилища, используя экспресс-сессию и паспорт.

Я использую passport, express-session и connect-pg-simple.

Проблема в том, что сессия неправильно получается из хранилища, где она корректно (надеюсь, но сомневаюсь) сохраняется.

Мои настройки такие же, как и во многих учебниках, которые я нашел.

сервер.js:

import express from 'express';
import next from 'next';
import bodyParser from 'body-parser';
import session from 'express-session';
import connectPgSimple from 'connect-pg-simple';
const sessionStorage = connectPgSimple(session);
import initAuthentication from '!/server/authentication';

const dev = process.env.NODE_ENV !== 'production'; // eslint-disable-line
const port = process.env.PORT || 3000; // eslint-disable-line
const app = next({ dev });

app.prepare()
.then(() => {
  const server = express();

  server.use(express.static('public'));

  /* Note Since version 1.5.0, the cookie-parser middleware no longer needs
     to be used for this module to work. This module now directly reads and writes
     cookies on req/res. Using cookie-parser may result in issues
     if the secret is not the same between this module and cookie-parser.
     https://www.npmjs.com/package/express-session */
  // server.use(cookieParser());

  server.use(bodyParser.json()); // for parsing application/json
  server.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
  server.use(session({
    secret: 'keyboard cat',
    store: new sessionStorage(),
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: false,
      maxAge: 30 * 24 * 60 * 60 * 1000
    }})
  );

  initAuthentication(server);
});

аутентификация.js:

import passport from 'passport';
import LocalStrategy from 'passport-local';
import bcrypt from 'bcrypt';
import {User} from '!/server/db';
import util from 'util';

User.prototype.validPassword = function(password) {
  return bcrypt.compareSync(password, this.passwordHash);
};

User.authenticate = (username, password, done) => {
  User.findOne({where: {nickname: username}}).then(user => {
    if (!user) {
      return done(null, false, { message: 'Неверное имя пользователя.' });
    }
    if (!user.validPassword(password)) {
      return done(null, false, { message: 'Неверный пароль.' });
    }
    return done(null, user);
  }).catch(err => {
    return done(err);
  });
};

export default function initAuthentication(server) {
  server.use(passport.initialize());
  server.use(passport.session());

  passport.use('local-signIn', new LocalStrategy(User.authenticate));

  passport.serializeUser((user, done) => {
    console.log('> serializeUser "'+user.nickname+'" ('+user.id+')');
    done(null, user.id);
  });
  passport.deserializeUser((id, done) => {
    console.log('> deserializeUser with id: ' + id)
    User.findById(id).then(user => {
      done(null, user);
    }).catch(error => {
      console.log('Error in passport.deserializeUser: ' + error);
      done(error, null);
    });
  });

  server.post('/user/login',
    passport.authenticate('local-signIn'),
    (req, res) => {
      // If this function gets called, authentication was successful.
      // `req.user` contains the authenticated user.
      console.log('Authenticated user "'+req.user.nickname+'"');
      req.login(req.user, (err)=> {
        if (err) console.log(err);
        console.log('\t Session established for user "'+req.user.nickname+'"');
        res.json(req.user);
      });
    }
  );

  function logAuthenticationStatus(req, res, next) {
    console.log('Authentication status:')
    console.log('\treq.cookies: ' + util.inspect(req.cookies));
    console.log('\treq.isAuthenticated: ', req.isAuthenticated());
    console.log('\treq.session: ', req.session);
    if (req.user) {
      console.log('\tLogged in as "'+req.user.nickname+'"');
    } else {
      console.log('\tNot logged in');
    }
    next();
  }

  server.use(logAuthenticationStatus);

  server.get('/logout', function(req, res){
    req.logout();
    res.redirect('/');
  });
}

Интересной частью является отладочный вывод «express-session», благодаря удивительному npm-пакету debug.

Итак, когда приходит запрос к /user/login с username=AntonAL, происходит следующее:

Executing (default): SELECT "id", "nickname", "email", "password", "passwordHash", "lastLoggedIn", "createdAt", "updatedAt" FROM "users" AS "user" WHERE "user"."nickname" = 'AntonAL' LIMIT 1;
> serializeUser "AntonAL" (1)
Authenticated user "AntonAL"
> serializeUser "AntonAL" (1)
     Session established for user "AntonAL"
  express-session saving qiQfhyAvDDPD7muJLtGdZudKqMug0aAC +23ms
  express-session split response +0ms
  express-session set-cookie connect.sid=s%3AqiQfhyAvDDPD7muJLtGdZudKqMug0aAC.0wIcunkcEjhaUzs4H7w4uuv6u%2FBKXMROuAm6%2FG0vVQw; Path=/; Expires=Sat, 30 Sep 2017 10:55:31 GMT; HttpOnly +1ms
info: POST /user/login 200 50ms statusCode=200, url=/user/login, host=localhost:3000, content-type=application/json, origin=http://localhost:3000, accept-encoding=gzip, deflate, connection=keep-alive, accept=application/json, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10sid6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, content-length=44, accept-language=ru, method=POST, httpVersion=1.1, originalUrl=/user/login, , responseTime=50, user=AntonAL

Итак, сессия сохранена в бд, проверим:

SELECT * FROM session WHERE sid='qiQfhyAvDDPD7muJLtGdZudKqMug0aAC';`

sid                |                                                                     sess                                                                      |       expire        
----------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+---------------------
qiQfhyAvDDPD7muJLtGdZudKqMug0aAC | {"cookie":{"originalMaxAge":2592000000,"expires":"2017-09-30T10:55:31.514Z","secure":false,"httpOnly":true,"path":"/"},"passport":{"user":1}} | 2017-09-30 13:55:32
(1 row)

Все идет нормально.

Теперь я запрашиваю домашнюю страницу веб-сайта и получаю следующее:

info: GET / 200 486ms statusCode=200, url=/, host=localhost:3000, accept-encoding=gzip, deflate, cookie=connect.sid=s%3AO6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE.M4iFzpVZP9fNa%2FLEomsMD8D9LjA1uFnDMnXT%2FHR3wyk; meteor_login_token=4YvVuK0V4adQJaMM2setEAx9_Ki7q6At19YfAvwyOJ8; _ga=GA1.1.1413606909.1501852025, connection=keep-alive, upgrade-insecure-requests=1, accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10sid6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, cache-control=max-age=0, accept-language=ru, method=GET, httpVersion=1.1, originalUrl=/, , responseTime=486, user=null
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +516ms
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +4ms
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +1ms
  express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +0ms
  express-session no session found +1ms
Authentication status:
    req.cookies: undefined
    req.isAuthenticated:  false
    req.session:  Session {
     cookie: 
         { path: '/',
         _expires: 2017-09-30T11:15:52.123Z,
         originalMaxAge: 2592000000,
         httpOnly: true,
         secure: false } }
     Not logged in
   express-session no session found +7ms

Я вижу, что «экспресс-сессия» пытается получить сессию с другим SID O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE, которого нет в базе данных.

Почему так происходит?

Насколько я знаю, он должен получить по SID = qiQfhyAvDDPD7muJLtGdZudKqMug0aAC

Какие проблемы могут быть с моей настройкой?

Один секретный ключ, «cookie-parser», не используется в соответствии с рекомендацией «Примечание. Начиная с версии 1.5.0 промежуточное программное обеспечение cookie-parser больше не требуется»…

Я полностью застрял с этим.

Пожалуйста помоги.


Что-то не так с генерацией sid

Когда я вручную изменяю сохраненный сеанс sid, чтобы он соответствовал тому, что запрашивает express-session,

UPDATE session SET sid='O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE' WHERE sid='qiQfhyAvDDPD7muJLtGdZudKqMug0aAC';

сеанс выбран правильно, и пользователь сохраняется:

express-session fetching O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +3s
  express-session session found +2ms
> deserializeUser with id: 1
Executing (default): SELECT "id", "nickname", "email", "password", "passwordHash", "lastLoggedIn", "createdAt", "updatedAt" FROM "users" AS "user" WHERE "user"."id" = 1;
Authentication status:
    req.cookies: undefined
    req.isAuthenticated:  true
    req.session:  Session {
  cookie: 
   { path: '/',
     _expires: 2017-09-30T10:55:31.514Z,
     originalMaxAge: 2592000000,
     httpOnly: true,
     secure: false },
  passport: { user: 1 } }
    Logged in as "AntonAL"
  express-session saving O6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE +577ms
  express-session split response +1ms
info: GET / 200 585ms statusCode=200, url=/, host=localhost:3000, accept-encoding=gzip, deflate, cookie=connect.sid=s%3AO6rS2cPlQ6JDaUUxxYRAg-VI5MmldaRE.M4iFzpVZP9fNa%2FLEomsMD8D9LjA1uFnDMnXT%2FHR3wyk; meteor_login_token=4YvVuK0V4adQJaMM2setEAx9_Ki7q6At19YfAvwyOJ8; _ga=GA1.1.1413606909.1501852025, connection=keep-alive, upgrade-insecure-requests=1, accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8, referer=http://localhost:3000/user/login, cache-control=max-age=0, accept-language=ru, method=GET, httpVersion=1.1, originalUrl=/, , responseTime=585, user=AntonAL

Итак, теперь понятно — параметр sid отличается при генерации сеанса и его извлечении.


person AntonAL    schedule 31.08.2017    source источник
comment
Изменится ли поведение, если вы используете cookie-parser ?   -  person Brahma Dev    schedule 07.09.2017
comment
@БрахмаДев, нет.   -  person AntonAL    schedule 07.09.2017


Ответы (1)


Догадаться.

В клиентском коде я использовал функцию fetch со следующим кодом:

fetch('/user/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(values)
});

Этот подход дал мне проблему, о которой идет речь.

Когда я изменил метод запроса на «GET» в маршрутах и ​​​​использовал простое перенаправление, все, что у меня получилось, заработало.

window.location.href = "/login?"+querystring.stringify(values);

Почему это происходит?

person AntonAL    schedule 07.09.2017
comment
Вам нужно использовать опцию credentials для отправки файлов cookie. developer.mozilla.org/en-US/docs/Web/ API/ - person Brahma Dev; 08.09.2017
comment
проверить заголовки в обоих запросах, отправленных от клиента - person tx fun; 09.09.2017