Passportjs 挂在 serializeUser 上
Passportjs hangs on serializeUser
我目前正在学习如何使用 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 函数时和呈现页面之前之间,这是我的 passport-config 文件:
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 查询和一个空白的错误页面。
我在 Whosebug 上看到了很多 similar 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;
## 在不反序列化用户的情况下设置 Passport 登录 ##
我认为你已经使用了 2016 年教程完成的一些折旧功能,2 年前,很多东西可能会在 2 年内发生变化,
假设您已经完成安装 node.js 的部分,让我们按照以下步骤重做。
为您的应用创建文件夹:
mkdir AuthApp
cd AuthApp
创建节点应用程序:
npm 初始化
系统会提示您为 Node 的 package.json 提供一些信息。只需按回车键直到最后保留默认配置。
接下来,我们需要一个 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,这是一个用于构建 Web 应用程序的框架,其灵感来自 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)设置。在下面,我们使用我们设置的端口变量调用 app.listen(),并通过一个简单的日志让我们知道它一切正常,以及应用程序正在监听哪个端口。
现在我们应该启动我们的应用程序以确保一切正常。只需在终端上输入以下命令:
节点index.js
您应该会看到消息:App listening on port 3000。如果不是这样,您可能错过了一步。返回并重试。
继续,让我们看看我们的页面是否被提供给客户端。转到您的网络浏览器并导航至 http://localhost:3000.
如果您能看到我们在 auth.html 中创建的页面,我们就可以开始了。
返回终端并使用 ctrl + c 停止应用程序。所以请记住,当我说启动应用程序时,你写 node 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() we’re using 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 和应用程序秘密变量以及我们将用于对用户进行身份验证的回调 URL。作为第二个参数,它需要一个函数,该函数将 return 用户提供的个人资料信息。
再往下,我们设置路由来提供身份验证。正如您在回调 URL 中看到的,我们将用户重定向到我们之前定义的 /error 和 /success 路由。我们正在使用 passport.authenticate,它尝试在其第一个参数上使用给定策略进行身份验证,在本例中为 facebook。您可能注意到我们这样做了两次。在第一个中,它将请求发送到我们的 Facebook 应用程序。第二个由回调 URL 触发,Facebook 将使用它来响应登录请求。
现在您需要创建一个 Facebook 应用程序。有关如何执行此操作的详细信息,请参阅 Facebook 非常详细的指南创建 Facebook 应用程序,其中提供了有关如何创建应用程序的分步说明。
创建应用程序后,转到应用程序配置页面上的“设置”。在那里你会看到你的应用程序 ID 和应用程序秘密。不要忘记用相应的值更改您在 index.js 文件中为它们声明的变量。
接下来,在“应用程序域”字段中输入“localhost”。然后,转到页面底部的添加平台并选择网站。使用 http://localhost:3000/auth/facebook/callback 作为站点 URL.
在左侧边栏的产品部分下,您应该会看到 Facebook 登录。点击进入。
最后,将有效 OAuth 重定向 URI 字段设置为 http://localhost:3000/auth/facebook/callback。
如果您现在启动应用程序并单击使用 Facebook 登录 link,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/ and the Authorization callback URL to http://localhost:3000/auth/github/callback,就像我们对 Facebook 所做的那样。
现在,只需重新启动节点服务器并尝试使用 GitHub link.
登录
护照设置过程结束。
存在问题的序列化用户的护照也包含在此
教程linkclick here to view it
您可以将两种类型的方法添加到模型中 - 1. 实例方法和 2. class 方法。更多信息请点击此处 => https://medium.com/@benjaminconant/defining-instance-methods-on-sequelize-js-models-dea36f478950
您可以像这样将 validatePassword
和 generateHash
方法指定为 User
模型的 class 方法
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;
问题不在于 passportjs,而在于 deserializeUser 方法中的续集查询:
User.user.findOne({where: {id: id}}).then(function(err, user) { ...
查询returns只有一个传递给.then()
函数的变量,所以把它改成这样:
User.user.findOne({where: {id: id}}).then(function(user) { ..
修正了我的错误。
我目前正在学习如何使用 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 函数时和呈现页面之前之间,这是我的 passport-config 文件:
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 查询和一个空白的错误页面。
我在 Whosebug 上看到了很多
更新
用户模型:
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;
## 在不反序列化用户的情况下设置 Passport 登录 ##
我认为你已经使用了 2016 年教程完成的一些折旧功能,2 年前,很多东西可能会在 2 年内发生变化,
假设您已经完成安装 node.js 的部分,让我们按照以下步骤重做。
为您的应用创建文件夹:
mkdir AuthApp cd AuthApp
创建节点应用程序: npm 初始化
系统会提示您为 Node 的 package.json 提供一些信息。只需按回车键直到最后保留默认配置。
接下来,我们需要一个 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,这是一个用于构建 Web 应用程序的框架,其灵感来自 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)设置。在下面,我们使用我们设置的端口变量调用 app.listen(),并通过一个简单的日志让我们知道它一切正常,以及应用程序正在监听哪个端口。
现在我们应该启动我们的应用程序以确保一切正常。只需在终端上输入以下命令:
节点index.js 您应该会看到消息:App listening on port 3000。如果不是这样,您可能错过了一步。返回并重试。
继续,让我们看看我们的页面是否被提供给客户端。转到您的网络浏览器并导航至 http://localhost:3000.
如果您能看到我们在 auth.html 中创建的页面,我们就可以开始了。
返回终端并使用 ctrl + c 停止应用程序。所以请记住,当我说启动应用程序时,你写 node 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() we’re using 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 和应用程序秘密变量以及我们将用于对用户进行身份验证的回调 URL。作为第二个参数,它需要一个函数,该函数将 return 用户提供的个人资料信息。
再往下,我们设置路由来提供身份验证。正如您在回调 URL 中看到的,我们将用户重定向到我们之前定义的 /error 和 /success 路由。我们正在使用 passport.authenticate,它尝试在其第一个参数上使用给定策略进行身份验证,在本例中为 facebook。您可能注意到我们这样做了两次。在第一个中,它将请求发送到我们的 Facebook 应用程序。第二个由回调 URL 触发,Facebook 将使用它来响应登录请求。
现在您需要创建一个 Facebook 应用程序。有关如何执行此操作的详细信息,请参阅 Facebook 非常详细的指南创建 Facebook 应用程序,其中提供了有关如何创建应用程序的分步说明。
创建应用程序后,转到应用程序配置页面上的“设置”。在那里你会看到你的应用程序 ID 和应用程序秘密。不要忘记用相应的值更改您在 index.js 文件中为它们声明的变量。
接下来,在“应用程序域”字段中输入“localhost”。然后,转到页面底部的添加平台并选择网站。使用 http://localhost:3000/auth/facebook/callback 作为站点 URL.
在左侧边栏的产品部分下,您应该会看到 Facebook 登录。点击进入。
最后,将有效 OAuth 重定向 URI 字段设置为 http://localhost:3000/auth/facebook/callback。
如果您现在启动应用程序并单击使用 Facebook 登录 link,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/ and the Authorization callback URL to http://localhost:3000/auth/github/callback,就像我们对 Facebook 所做的那样。
现在,只需重新启动节点服务器并尝试使用 GitHub link.
登录护照设置过程结束。
存在问题的序列化用户的护照也包含在此 教程linkclick here to view it
您可以将两种类型的方法添加到模型中 - 1. 实例方法和 2. class 方法。更多信息请点击此处 => https://medium.com/@benjaminconant/defining-instance-methods-on-sequelize-js-models-dea36f478950
您可以像这样将 validatePassword
和 generateHash
方法指定为 User
模型的 class 方法
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;
问题不在于 passportjs,而在于 deserializeUser 方法中的续集查询:
User.user.findOne({where: {id: id}}).then(function(err, user) { ...
查询returns只有一个传递给.then()
函数的变量,所以把它改成这样:
User.user.findOne({where: {id: id}}).then(function(user) { ..
修正了我的错误。