Passportjs висит на serializeUser - PullRequest
       30

Passportjs висит на serializeUser

0 голосов
/ 04 сентября 2018

В настоящее время я изучаю, как аутентифицировать пользователей, используя Passportjs и локальную стратегию. Я следовал этому уроку здесь: https://scotch.io/tutorials/easy-node-authentication-setup-and-local. Я внес некоторые изменения, чтобы использовать sequelize вместо mongoose, и теперь, когда Я вхожу, я перенаправлен на пустую страницу с ошибкой.

Журналы консоли показывают:

Login Requested
Executing (default): SELECT `id`, `localemail`, `localpassword`, 
`facebookid`, `facebooktoken`, `facebookname`, `facebookemail`, 
`twitterid`, `twittertoken`, `twitterdisplayname`, `twitterusername`, 
`googleid`, `googletoken`, `googleemail`, `googlename`, `createdAt`, 
`updatedAt` FROM `Users` AS `User` WHERE `User`.`localemail` = 
'test@test.co.uk' LIMIT 1;
User found and logged in: 6
Serializing User: 6
POST /login 302 118.674 ms - 60
Executing (default): SELECT `id`, `localemail`, `localpassword`, 
`facebookid`, `facebooktoken`, `facebookname`, `facebookemail`, 
`twitterid`, `twittertoken`, `twitterdisplayname`, `twitterusername`, 
`googleid`, `googletoken`, `googleemail`, `googlename`, `createdAt`, 
`updatedAt` FROM `Users` AS `User` WHERE `User`.`id` = 6;

Я полагаю, что я сузил проблему до того момента, когда вызывается функция serializeUser, и до того, как страница отображается, вот мой файл конфигурации паспорта:

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user');
const bcrypt= require('bcrypt-nodejs');

passport.serializeUser(function(user, done) {
  console.log('Serializing User: ' + user.id);
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.user.findOne({where: {id: id}}).then(function(err, user) {
    return done(err, user);
  }).catch(function(err) {
    return done(err);
  });
});

passport.use('local-signup', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
  },
  function(req, email, password, done) {
    process.nextTick(function() {
      User.user.findOne({where: {localemail: email}}).then(function(user) {
        if (user) {
          return done(null, false,
              req.flash('signupMessage', 'That email is already taken.'));
        } else {
          let newUser = new User.user();
          console.log(newUser);
          newUser.localemail = email;
          newUser.localpassword = User.generateHash(password);
          newUser.save().then(function(user) {
            return done(null, user);
          }).catch(function(err) {
            return done(err);
          });
        }
      }).catch(function(err) {
        return done(err);
      });
    });
  }
));

passport.use('local-login', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
  },
  function(req, email, password, done) {
    User.user.findOne({where: {localemail: email}}).then(function(user) {
      if (!user) {
        console.log('No User found!');
        return done(null, false, req.flash('loginMessage', 'No user found'));
      }
      if (!User.validPassword(password, user)) {
        console.log('Incorrect Password');
        return done(null, false, req.flash('loginMessage', 'Wrong password.'));
      }
      console.log('User found and logged in: ' + user.id);
      return done(null, user);
    }).catch(function(err) {
      return done(err);
    });
  }
));

module.exports = passport;

И маршруты для входа и перенаправления успеха:

router.post('/login', function(req, res, next) {
  console.log('Login Requested');
  next();
}, passport.authenticate('local-login', {
  successRedirect: '/profile',
  failureRedirect: '/login',
  failureFlash: true,
}));

Я получаю одинаковые результаты независимо от того, на какую страницу я захожу после попытки входа в систему, повторения SQL-запроса в консоли и пустой страницы с ошибками. Я видел множество проблем похожих на этого в стеке, но после попытки решения ничего не помогло.

Обновление

Модель пользователя:

const Sequleize = require('sequelize');
const db = require('../config/database');
const bcrypt= require('bcrypt-nodejs');


let user = db.define('User', {
  localemail: Sequleize.STRING,
  localpassword: Sequleize.STRING,

  facebookid: Sequleize.STRING,
  facebooktoken: Sequleize.STRING,
  facebookname: Sequleize.STRING,
  facebookemail: Sequleize.STRING,

  twitterid: Sequleize.STRING,
  twittertoken: Sequleize.STRING,
  twitterdisplayname: Sequleize.STRING,
  twitterusername: Sequleize.STRING,

  googleid: Sequleize.STRING,
  googletoken: Sequleize.STRING,
  googleemail: Sequleize.STRING,
  googlename: Sequleize.STRING,
});

db.sync();

exports.validPassword = function(password, user) {
  return bcrypt.compareSync(password, user.localpassword);
};

exports.generateHash = function(password) {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};

exports.user = user;

Ответы [ 3 ]

0 голосов
/ 05 сентября 2018

Существует два типа методов, которые вы можете добавить в модель - 1. метод экземпляра и 2. метод класса. Подробнее об этом здесь => https://medium.com/@benjaminconant/defining-instance-methods-on-sequelize-js-models-dea36f478950

Вы можете указать свои validatePassword и generateHash методы как методы класса User модели, например,

const Sequleize = require('sequelize');
const db = require('../config/database');
const bcrypt= require('bcrypt-nodejs');


let User = db.define('User', {
  localemail: Sequleize.STRING,
  localpassword: Sequleize.STRING,

  facebookid: Sequleize.STRING,
  facebooktoken: Sequleize.STRING,
  facebookname: Sequleize.STRING,
  facebookemail: Sequleize.STRING,

  twitterid: Sequleize.STRING,
  twittertoken: Sequleize.STRING,
  twitterdisplayname: Sequleize.STRING,
  twitterusername: Sequleize.STRING,

  googleid: Sequleize.STRING,
  googletoken: Sequleize.STRING,
  googleemail: Sequleize.STRING,
  googlename: Sequleize.STRING,
}, {
    classMethods: {
        validPassword: function(password, user) {
            return bcrypt.compareSync(password, user.localpassword);
        };

        generateHash: function(password) {
            return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
        };
    }    
});

module.exports = User;

Теперь вы можете использовать User модель, например,

passport.deserializeUser(function(id, done) {
  User.findOne({where: {id: id}}).then(function(err, user) {
    return done(err, user);
  }).catch(function(err) {
    return done(err);
  });
});

passport.use('local-signup', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
  },
  function(req, email, password, done) {
    process.nextTick(function() {
      User.findOne({where: {localemail: email}}).then(function(user) {
        if (user) {
          return done(null, false,
              req.flash('signupMessage', 'That email is already taken.'));
        } else {
          let newUser = new User();
          console.log(newUser);
          newUser.localemail = email;
          newUser.localpassword = User.generateHash(password);
          newUser.save().then(function(user) {
            return done(null, user);
          }).catch(function(err) {
            return done(err);
          });
        }
      }).catch(function(err) {
        return done(err);
      });
    });
  }
)); 

passport.use('local-login', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
  },
  function(req, email, password, done) {
    User.findOne({where: {localemail: email}}).then(function(user) {
      if (!user) {
        console.log('No User found!');
        return done(null, false, req.flash('loginMessage', 'No user found'));
      }
      if (!User.validPassword(password, user)) {
        console.log('Incorrect Password');
        return done(null, false, req.flash('loginMessage', 'Wrong password.'));
      }
      console.log('User found and logged in: ' + user.id);
      return done(null, user);
    }).catch(function(err) {
      return done(err);
    });
  }
));

module.exports = passport;
0 голосов
/ 08 сентября 2018

Проблема была не в passportjs, а в моем запросе sequelize в методе deserializeUser:

User.user.findOne({where: {id: id}}).then(function(err, user) { ...

Запрос возвращает только одну переменную, которая передается в функцию .then(), поэтому измените ее следующим образом:

User.user.findOne({where: {id: id}}).then(function(user) { ..

исправил мою ошибку.

0 голосов
/ 04 сентября 2018

## Настройка паспортного входа без deserializeUser ##

Я думаю, что вы использовали некоторые устаревшие функции, которые были сделаны в учебнике 2016 года, 2 года назад, множество вещей может измениться в течение 2 лет,

давайте повторим это, выполнив следующие шаги, предполагая, что вы уже завершили часть установки node.js.

создайте папку для вашего приложения:

mkdir AuthApp CD AuthApp

создать приложение узла: npm init

Вам будет предложено предоставить некоторую информацию для пакета Node package.json. Просто нажмите Enter до конца, чтобы выйти из конфигурации по умолчанию.

Далее нам потребуется файл HTML для отправки клиенту. Создайте файл с именем auth.html в корневой папке вашего приложения, не собираясь использовать столько html, сколько мы собираемся сделать это для тестирования:

<html>
<head>
<title>Node.js OAuth</title>
</head>
<body>
<a href=auth/facebook>Sign in with Facebook</a>
<br></br>
<a href=auth/github>Sign in with Github</a>
</body>
</html>

Вам также потребуется Express, платформа для создания веб-приложений, вдохновленная Sinatra от Ruby. Чтобы установить Express, введите в терминале следующую команду:

npm установить экспресс --save Как только вы это сделаете, пришло время написать код.

Создайте файл index.js в корневой папке вашего приложения и добавьте в него следующее содержимое:

/*  EXPRESS SETUP  */
const express = require('express');
const app = express();
app.get('/', (req, res) => res.sendFile('auth.html', { root : __dirname}));
const port = process.env.PORT || 3000;
app.listen(port , () => console.log('App listening on port ' + port));

В приведенном выше коде нам требуется Express и создайте наше приложение Express, вызвав express (). Затем мы объявляем маршрут для домашней страницы нашего приложения. Там мы отправляем созданный нами HTML-файл клиенту, обращающемуся по этому маршруту. Затем мы используем process.env.PORT, чтобы установить для порта переменную окружения, если она существует. В противном случае мы будем использовать значение по умолчанию 3000, то есть порт, который мы будем использовать локально. Это дает вам достаточно гибкости для перехода от разработки непосредственно к производственной среде, где порт может быть установлен поставщиком услуг, таким как, например, Heroku. Чуть ниже мы вызываем app.listen () с установленной нами переменной порта и простым журналом, чтобы сообщить нам, что все работает нормально и на каком порту прослушивает приложение.

Теперь мы должны запустить наше приложение, чтобы убедиться, что все работает правильно. Просто напишите на терминале следующую команду:

узел index.js Вы должны увидеть сообщение: Приложение прослушивает порт 3000. Если это не так, вы, вероятно, пропустили шаг. Вернитесь и попробуйте снова.

Идем дальше, давайте посмотрим, обслуживается ли наша страница клиенту. Перейдите в веб-браузер и перейдите к http://localhost:3000.

Если вы видите страницу, которую мы создали в auth.html, мы готовы.

Вернитесь к терминалу и остановите приложение, нажав Ctrl + C. Поэтому помните, что когда я говорю «запустить приложение», вы пишете узел index.js, а когда я говорю «остановить приложение», вы делаете Ctrl + C. Очистить? Хорошо, вы только что запрограммированы: -)

Настройка паспорта Как вы скоро поймете, Passport делает легким предоставление аутентификации для наших пользователей. Давайте установим Passport с помощью следующей команды:

npm установить паспорт --save Теперь мы должны настроить паспорт. Добавьте следующий код внизу файла index.js:

/*  PASSPORT SETUP  */

const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
app.get('/success', (req, res) => res.send("You have successfully logged in"));
app.get('/error', (req, res) => res.send("error logging in"));

passport.serializeUser(function(user, cb) {
cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
cb(null, obj);
});

Здесь нам требуется Passport и инициализировать его вместе с промежуточным программным обеспечением для аутентификации сеанса непосредственно в нашем приложении Express. Затем мы устанавливаем маршруты «/ success» и «/ error», которые будут отображать сообщение о том, как прошла аутентификация. Это тот же синтаксис для нашего последнего маршрута, только на этот раз вместо использования res.SendFile () мы используем res.send () , который будет отображать данную строку как текст / HTML в браузере. Затем мы используем обратные вызовы serializeUser и deserializeUser. Первый будет вызываться при аутентификации, и его задача - сериализовать пользовательский экземпляр и сохранить его в сеансе с помощью файла cookie. Второй будет вызываться при каждом последующем запросе на десериализацию экземпляра, предоставляя ему уникальный идентификатор cookie в качестве «учетных данных». Подробнее об этом вы можете прочитать в паспортной документации.

Как примечание, этот очень простой образецнаше приложение будет прекрасно работать без deserializeUser, но оно убивает цель сохранения сеанса, что вам нужно в каждом приложении, требующем входа в систему.

Это все, что нужно для настройки паспорта. Теперь мы наконец можем заняться бизнесом.

Реализация аутентификации Facebook Первое, что нам нужно сделать, чтобы обеспечить аутентификацию Facebook, это установить пакет passport-facebook. Вы знаете, как это происходит:

npm install passport-facebook --save

Теперь, когда все настроено, добавить аутентификацию Facebook очень просто. Добавьте следующий код внизу файла index.js:

/*  FACEBOOK AUTH  */

const FacebookStrategy = require('passport-facebook').Strategy;
const FACEBOOK_APP_ID = 'your app id';
const FACEBOOK_APP_SECRET = 'your app secret';
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, cb) {
  return cb(null, profile);
}
));

app.get('/auth/facebook',
passport.authenticate('facebook'));

app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/error' }),
function(req, res) {
res.redirect('/success');
});

Давайте пройдемся по этому блоку кода шаг за шагом. Во-первых, нам требуется модуль passport-facebook. Затем мы объявляем переменные, в которых мы будем хранить наш идентификатор приложения и секрет приложения (вскоре мы увидим, как их получить). После этого мы сообщаем Passport использовать экземпляр FacebookStrategy, который нам необходим. Чтобы реализовать указанную стратегию, мы даем ей наш идентификатор приложения и секретные переменные приложения, а также callbackURL, который мы будем использовать для аутентификации пользователя. В качестве второго параметра требуется функция, которая будет возвращать информацию профиля, предоставленную пользователем.

Далее мы настраиваем маршруты для обеспечения аутентификации. Как вы можете видеть в callbackURL, мы перенаправляем пользователя на маршруты / error и / success, которые мы определили ранее. Мы используем passport.authenticate, который пытается аутентифицироваться с помощью данной стратегии по ее первому параметру, в данном случае это Facebook. Вы, наверное, заметили, что мы делаем это дважды. На первом он отправляет запрос в наше приложение Facebook. Второй вызывается URL-адресом обратного вызова, который Facebook будет использовать для ответа на запрос входа в систему.

Теперь вам нужно создать приложение для Facebook. Подробнее о том, как это сделать, см. Очень подробное руководство Facebook «Создание приложения Facebook», в котором приведены пошаговые инструкции по его созданию.

Когда ваше приложение будет создано, перейдите в Настройки на странице конфигурации приложения. Там вы увидите свой идентификатор приложения и секрет приложения. Не забудьте заменить переменные, которые вы объявили для них в файле index.js, на соответствующие им значения.

Далее введите «localhost» в поле «Домены приложения». Затем перейдите к Добавить платформу внизу страницы и выберите Веб-сайт. Используйте http://localhost:3000/auth/facebook/callback в качестве URL сайта.

На левой боковой панели, под разделом Продукты, вы должны увидеть Facebook Login. Нажмите, чтобы попасть туда.

И, наконец, установите для поля Допустимые URI перенаправления OAuth значение http://localhost:3000/auth/facebook/callback.

Если вы запустите приложение сейчас и нажмете ссылку «Войти через Facebook», Facebook попросит вас предоставить необходимую информацию, и после входа в систему вы будете перенаправлены на маршрут / success, где вы вы увидите сообщение, что вы успешно вошли в систему.

Вот и все! Вы только что настроили аутентификацию Facebook. Довольно просто, правда?

Реализация аутентификации GitHub Процесс добавления аутентификации GitHub очень похож на то, что мы сделали для Facebook. Сначала мы установим модуль passport-github:

npm install passport-github --save

Теперь перейдите в файл index.js и добавьте следующие строки внизу:

/*  GITHUB AUTH  */

const GitHubStrategy = require('passport-github').Strategy;

const GITHUB_CLIENT_ID = "your app id"
const GITHUB_CLIENT_SECRET = "your app secret";

passport.use(new GitHubStrategy({
clientID: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
callbackURL: "/auth/github/callback"
},
function(accessToken, refreshToken, profile, cb) {
  return cb(null, profile);
}
));

app.get('/auth/github',
passport.authenticate('github'));

app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/error' }),
function(req, res) {
res.redirect('/success');
});

Это выглядит знакомо! Это практически так же, как и раньше. Единственное отличие состоит в том, что мы используем GithubStrategy вместо FacebookStrategy.

Пока что ... то же самое. Если вы еще не поняли, то следующим шагом будет создание нашего приложения GitHub. GitHub имеет очень простое руководство по созданию приложения GitHub, которое проведет вас через этот процесс.

Когда вы закончите, на панели конфигурации вам нужно будет установить URL-адрес домашней страницы на http://localhost:3000/ и URL-адрес обратного вызова авторизации на http://localhost:3000/auth/github/callback,, как мы это делали в Facebook.

Теперь просто перезапустите сервер Node и попробуйте войти в систему, используя ссылку GitHub.

Конец процесса настройки паспорта.

паспортов с сериализованными пользователями, где ваш профессионалБлем существует и покрыт в этом учебная ссылка нажмите здесь, чтобы посмотреть

...