我目前正在学习如何使用Passportjs和本地策略对用户进行身份验证,我一直在关注此教程:https://scotch.io/tutorials/easy-node-authentication-setup-and-local。我已经进行了一些更改,以使用sequelize代替猫鼬,现在登录时,我被重定向到一个空白错误页面。
控制台日志显示:
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查询以及空白错误页面,我都得到相同的结果。 我在stackoverflow上看到了很多issues similar to this,但是在尝试解决方案后没有任何效果。
更新
用户模型:
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;
答案 0 :(得分:0)
##设置护照登录而无需反序列化用户##
我认为您已经使用了2年前于2016年完成的折旧函数,事情的负载可能会在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,这是一个受Ruby的Sinatra启发而构建网络应用程序的框架。为了安装Express,从终端输入以下命令:
npm install express-保存 完成此操作后,就该编写一些代码了。
在应用程序的根文件夹中创建一个文件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)设置。在下面,我们使用设置的port变量调用app.listen(),并通过简单的日志告诉我们它们一切正常,并且正在监听应用程序的端口。
现在,我们应该启动我们的应用程序,以确保所有功能均正常运行。只需在终端上编写以下命令:
节点index.js 您应该会看到以下消息:App正在监听3000端口。如果不是这种情况,则可能错过了一步。返回并重试。
继续,让我们看看是否将我们的页面提供给客户。转到网络浏览器并导航到http://localhost:3000。
如果您可以看到我们在auth.html中创建的页面,那就很好了。
返回终端并使用ctrl + c停止应用程序。所以请记住,当我说启动应用程序时,编写节点index.js,而当我说停止应用程序时,则执行ctrl + c。明确?好,您刚刚被编程了:-)
设置护照 您很快就会意识到,Passport使为我们的用户提供身份验证变得轻而易举。让我们使用以下命令安装Passport:
npm安装护照-保存 现在我们必须设置Passport。在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(),这将在浏览器中将给定的字符串呈现为text / html。然后,我们使用serializeUser和deserializeUser回调。第一个将在身份验证时被调用,其工作是序列化用户实例并通过cookie将其存储在会话中。第二个请求将在随后的每个请求中被调用以反序列化该实例,并为其提供唯一的cookie标识符作为“凭据”。您可以在Passport文档中阅读有关此内容的更多信息。
作为一个附带说明,我们的这个非常简单的示例应用程序在没有deserializeUser的情况下也可以正常工作,但是它杀死了保持会话的目的,而这在每个需要登录的应用程序中都需要。
仅用于实际的Passport设置。现在我们终于可以开始业务了。
实施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模块。然后,我们声明用于存储应用ID和应用密钥的变量(我们将很快了解如何获取这些变量)。之后,我们告诉Passport使用所需的FacebookStrategy实例。为了实例化上述策略,我们为它提供了应用ID和应用机密变量以及用于验证用户身份的callbackURL。作为第二个参数,它使用一个函数,该函数将返回用户提供的配置文件信息。
进一步,我们设置了路由以提供身份验证。如您在callbackURL中所见,我们将用户重定向到我们之前定义的/ error和/ success路由。我们使用的是password.authenticate,它会尝试使用第一个参数(在本例中为facebook)的给定策略进行身份验证。您可能已经注意到我们做了两次。在第一个应用程序上,它将请求发送到我们的Facebook应用程序。第二个是由回调URL触发的,Facebook将使用该URL来响应登录请求。
现在,您需要创建一个Facebook应用。有关如何执行此操作的详细信息,请参阅Facebook非常详细的指南“创建Facebook应用程序”,其中提供了有关如何创建应用程序的逐步说明。
创建应用程序后,请转到应用程序配置页面上的“设置”。在这里,您会看到自己的应用程序ID和应用程序密码。不要忘记使用相应的值更改在index.js文件中为它们声明的变量。
接下来,在“应用程序域”字段中输入“ localhost”。然后,转到页面底部的“添加平台”,然后选择“网站”。使用http://localhost:3000/auth/facebook/callback作为网站URL。
在左侧边栏的“产品”部分下,您应该看到Facebook登录。点击进入那里。
最后,将有效OAuth重定向URI字段设置为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 App。 GitHub有一个非常简单的指南,即创建GitHub应用程序,它将指导您完成该过程。
完成后,就像在Facebook上一样,您需要在配置面板中将主页URL设置为http://localhost:3000/,将授权回调URL设置为http://localhost:3000/auth/github/callback。
现在,只需重启Node服务器并尝试使用GitHub链接登录。
“护照设置”过程结束。
本问题涵盖了存在问题的序列化用户的护照 教程链接click here to view it
答案 1 :(得分:0)
可以向模型添加两种类型的方法-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;
答案 2 :(得分:0)
问题不在于passportjs,而是我在deserializeUser方法中的续集查询:
User.user.findOne({where: {id: id}}).then(function(err, user) { ...
查询仅返回一个传递给.then()
函数的变量,因此将其更改为:
User.user.findOne({where: {id: id}}).then(function(user) { ..
修复了我的错误。