在 Node.js 中解释护照
Passport 非常容易集成 NodeJs 包,用于向我们的网站或 Web 应用程序添加身份验证功能。
为了展示 Passport 在 Nodejs 中的使用,我们从创建一个非常简单的 Node 应用程序开始。
使用 express 创建一个简单的 Node 应用程序:
步骤1:创建一个新文件夹(我将文件夹命名为“NODEAPP”),并在其中创建一个名为“Server.js”的新文件。
第 2 步:使用命令“npm init -y”初始化 npm。 Package.json 文件将被添加到您的项目文件夹中。
npm init-y
第三步:安装所有必要的包,即express 、 body-parser (稍后将用于获取 HTML 表单数据)、 mongoose (用于连接到我们的 MongoDB 数据库),使用命令:
npm install express body-parser mongoose
1 个名为“ package-lock.json ”的文件将添加到您的项目结构中,1 个名为“ node_modules ”的文件夹将在执行上述命令后添加到您的项目结构中。
项目结构:最终的项目结构应如下所示:
第 4 步:将基本代码添加到我们的Server.js文件中。
Server.js
// Telling node to include the following
// external modules
var express = require('express');
var app = express();
// Mongoose for connecting to our database
const mongoose = require("mongoose");
// Body parser to fetch HTML form data later on
const bodyParser = require("body-parser");
// Connecting mongoose to our database
// named "userDatabase"
mongoose.connect(
'mongodb://localhost:27017/userDatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// Handling get request on home route.
app.get("/", function (req, res) {
res.send("This is the home route");
});
// Allowing app to listen on port 3000
app.listen(3000, function () {
console.log("server started successfully");
})
Server.js
/*We are going to add simple authentication to our website
We are going to collect data(email and password) entered by
user in the HTML form, created in the INDEX.HTML file, and
we are going to store that data in our database
this is how we can simply register any new user */
/* if we want to log in our already registered user,
then we collect email and password from HTML
form created in LOGIN.HTML file, and
we can find data(if any) associated with this
email, and return it to user */
var express = require('express');
var app = express();
const bodyParser = require("body-parser");
// Allowing app to use body parser
app.use(bodyParser.urlencoded({extended:true}));
// Connecting mongoose to our database
// named "userDatabase"
mongoose.connect(
'mongodb://localhost:27017/userDatabase' {
useNewUrlParser: true,
useUnifiedTopology: true
});
const userSchema = new mongoose.Schema({
email: String,
password: String
});
// Creating the User model.
const User = new mongoose.model("User", userSchema);
/* setting a simple get request on the home route,
and sending our index.html file containing a form
which will allow user to enter his details and
register. */
app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
})
app.get("/login", function(req, res) {
res.sendFile(__dirname + "/login.html");
})
// Handling the post request on /register route.
app.post("/register", function(req, res){
console.log(req.body);
// Getting the email and password entered
// by the user
var email = req.body.username;
var password = req.body.password;
// Creating a new user with entered credentials.
var newuser = new User({
email : email,
password : password
})
// Saving the newuser.
newuser.save();
console.log("saved successfully");
// Sending the response that user
// is saved successfully
res.send("saved successfully");
})
APP.post("/login", function(req, res) {
console.log(req.body);
// Getting the email and password entered
// by the user
var emailEntered = req.body.username;
var passwordEntered = req.body.password;
// Checking if the email entered exists
// in database or not.
User.findOne({email : emailEntered},
function(err, data){
if(data) {
// The email exists in the database.
console.log(data);
/* checking if the password entered
is matching the original password */
if(data.password == passwordEntered){
res.send("login successful!");
}
else {
// Password is incorrect.
res.send("Incorrect Password");
}
}
else {
// The email does not exist in the database
console.log(err);
}
});
})
// Allowing app to listen on port 3000
app.listen(3000, function () {
console.log("server started successfully");
})
Index.html
Page Title
Login.html
Server.js
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
app.use(express.static("public"));
app.use(bodyParser.urlencoded({extended:true}));
// Below all the app.use methods
app.use(session({
secret : "any long secret key",
resave : false,
saveUninitialized : false
}));
Server.js
app.use(session({
secret: "any long secret key",
resave: false,
saveUninitialized: false
}));
// Initializing Passport
app.use(passport.initialize());
// Starting the session
app.use(passport.session());
// Creating user schema and adding a plugin to it
const userSchema = new mongoose.Schema({
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
Server.js
const User = new mongoose.model("User", userSchema);
passport.use(User.createStrategy());
// Serializing and deserializing
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
Server.js
// Handling get request on the home and login route
app.get("/", function (req, res) {
/* req.isAuthentcated() returns true or
false depending upon whether a session
is already running or not.*/
if(req.isAuthenticated()) {
/* if the request is already authenticated,
i.e. the user has already logged in and
there is no need to login again. Or we
can say, the session is running. */
res.send("
You have already logged in. No need to login again");
}
else{
// If the user is new and no session
// is Running already
res.sendFile(__dirname + "/index.html");
}
})
// Handling get request on login route
app.get("/login", function(req, res) {
if(req.isAuthenticated()){
/* if request is already authenticated,
i.e. user has already logged in and
there is no need to login again. */
res.send("
You have already logged in. No need to login again");
}
else{
res.sendFile(__dirname + "/login.html");
}
})
Server.js
/* The index.html file will be same as that
used in the earlier method of authentication*/
app.post("/register", function(req, res){
console.log(req.body);
// Getting Email and PAssword Entered by user
var email = req.body.username;
var password = req.body.password;
/* Registering the user with email and
password in our database
and the model used is "User" */
User.register({ username : email },
req.body.password, function (err, user) {
if (err) {
// if some error is occurring, log that error
console.log(err);
}
else {
passport.authenticate("local")
(req, res, function() {
res.send("successfully saved!");
})
}
})
})
Server.js
// All handling related to login is done below.
// Here we are handling the post request on
// /login route
app.post("/login", function (req, res) {
console.log(req.body);
const userToBeChecked = new User({
username: req.body.username,
password: req.body.password,
});
// Checking if user if correct or not
req.login(userToBeChecked, function (err) {
if (err) {
console.log(err);
// If authentication fails, then coming
// back to login.html page
res.redirect("/login");
} else {
passport.authenticate("local")(
req, res, function () {
User.find({ email: req.user.username },
function (err, docs) {
if (err) {
console.log(err);
} else {
//login is successful
console.log("credentials are correct");
res.send("login successful");
}
});
});
}
});
});
Index.html
Page Title
REGISTER
Login.html
LOGIN
Server.js
var express = require('express');
var app = express();
const mongoose = require("mongoose");
/* Requiring body-parser package
to fetch the data that is entered
by the user in the HTML form.*/
const bodyParser = require("body-parser");
// Telling our Node app to include all these modules
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose =
require("passport-local-mongoose");
// Allowing app to use body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: "long secret key",
resave: false,
saveUninitialized: false
}));
// Initializing Passport
app.use(passport.initialize());
// Starting the session
app.use(passport.session());
// Connecting mongoose to our database
mongoose.connect(
'mongodb://localhost:27017/userDatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
/* Creating the schema of user which now
include only email and password for
simplicity.*/
const userSchema = new mongoose.Schema({
email: String,
password: String
});
/* Just after the creation of userSchema,
we add passportLocalMongoose plugin
to our Schema */
userSchema.plugin(passportLocalMongoose);
// Creating the User model
const User = new mongoose.model("User", userSchema);
/* After the creation of mongoose model,
we have to write the following code */
passport.use(User.createStrategy());
// Serializing and deserializing
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// Handling get request on the home route
app.get("/", function (req, res) {
/* req.isAuthentcated() returns true or
false depending upon whether a session is
already running or not. */
if (req.isAuthenticated()) {
/* if request is already authenticated,
i.e. user has already logged in and
there is no need to login again or
we can say, session is running.*/
res.send(
"You have already logged in. No need to login again");
}
else {
// If the user is new and
// no session is Running already
res.sendFile(__dirname + "/index.html");
}
})
// Handling get request on login route
app.get("/login", function (req, res) {
if (req.isAuthenticated()) {
/* If request is already authenticated,
i.e. user has already logged in and
there is no need to login again. */
res.send(
"You have already logged in. No need to login again");
}
else {
/* if session has expired, then user
need to login back again and
we will send the Login.html */
res.sendFile(__dirname + "/login.html");
}
})
/* Registering the user for the first time
handling the post request on /register route.*/
app.post("/register", function (req, res) {
console.log(req.body);
var email = req.body.username;
var password = req.body.password;
User.register({ username: email },
req.body.password, function (err, user) {
if (err) {
console.log(err);
}
else {
passport.authenticate("local")
(req, res, function () {
res.send("successfully saved!");
})
}
})
})
// Handling the post request on /login route
app.post("/login", function (req, res) {
console.log(req.body);
const userToBeChecked = new User({
username: req.body.username,
password: req.body.password
});
// Checking if user if correct or not
req.login(userToBeChecked, function (err) {
if (err) {
console.log(err);
res.redirect("/login");
}
else {
passport.authenticate("local")
(req, res,function () {
User.find({ email: req.user.username },
function (err, docs) {
if (err) {
console.log(err);
}
else {
//login is successful
console.log("credentials are correct");
res.send("login successful");
}
});
});
}
})
})
// Allowing app to listen on port 3000
app.listen(3000, function () {
console.log("server started successfully");
})
第 5 步:您也可以通过打开浏览器并输入http://localhost:3000来检查。您应该会看到一个带有以下响应的白页。
第 6 步:向我们的网站添加身份验证。向我们的网站添加身份验证功能的一种简单方法是获取用户输入的电子邮件和密码,并将其直接保存在数据库中。同样,当用户想登录时,询问他/她的邮箱和密码,如果有任何记录与输入的邮箱和密码匹配,则该用户是真实的并且登录成功。
服务器.js
/*We are going to add simple authentication to our website
We are going to collect data(email and password) entered by
user in the HTML form, created in the INDEX.HTML file, and
we are going to store that data in our database
this is how we can simply register any new user */
/* if we want to log in our already registered user,
then we collect email and password from HTML
form created in LOGIN.HTML file, and
we can find data(if any) associated with this
email, and return it to user */
var express = require('express');
var app = express();
const bodyParser = require("body-parser");
// Allowing app to use body parser
app.use(bodyParser.urlencoded({extended:true}));
// Connecting mongoose to our database
// named "userDatabase"
mongoose.connect(
'mongodb://localhost:27017/userDatabase' {
useNewUrlParser: true,
useUnifiedTopology: true
});
const userSchema = new mongoose.Schema({
email: String,
password: String
});
// Creating the User model.
const User = new mongoose.model("User", userSchema);
/* setting a simple get request on the home route,
and sending our index.html file containing a form
which will allow user to enter his details and
register. */
app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
})
app.get("/login", function(req, res) {
res.sendFile(__dirname + "/login.html");
})
// Handling the post request on /register route.
app.post("/register", function(req, res){
console.log(req.body);
// Getting the email and password entered
// by the user
var email = req.body.username;
var password = req.body.password;
// Creating a new user with entered credentials.
var newuser = new User({
email : email,
password : password
})
// Saving the newuser.
newuser.save();
console.log("saved successfully");
// Sending the response that user
// is saved successfully
res.send("saved successfully");
})
APP.post("/login", function(req, res) {
console.log(req.body);
// Getting the email and password entered
// by the user
var emailEntered = req.body.username;
var passwordEntered = req.body.password;
// Checking if the email entered exists
// in database or not.
User.findOne({email : emailEntered},
function(err, data){
if(data) {
// The email exists in the database.
console.log(data);
/* checking if the password entered
is matching the original password */
if(data.password == passwordEntered){
res.send("login successful!");
}
else {
// Password is incorrect.
res.send("Incorrect Password");
}
}
else {
// The email does not exist in the database
console.log(err);
}
});
})
// Allowing app to listen on port 3000
app.listen(3000, function () {
console.log("server started successfully");
})
索引.html
Page Title
登录.html
但是使用这种简单的身份验证方法有一些限制。
- 用户在注册过程中输入的密码对数据库中的每个人都是公开的,即组织中任何有权访问数据库的人都可以看到任何用户的密码。但是,密码不能暴露,我们需要强大的加密,以便我们可以将密码安全地存储在数据库中。
- 每次(可能每天 20-25 次甚至更多)我们想要使用这个网络应用程序或网站,我们都必须重新输入我们的电子邮件和密码,这变得非常耗时。
- 我们无法使用这个简单的验证码添加社交网络登录功能。
Passport 为我们消除了所有这些限制。如果我们使用 Passport,那么:
- 我们不必暴露我们的密码。整个加密和解密过程由 Passport 完成,包括密码的散列和加密。
- Passport 允许我们创建和维护会话。例如,当您访问任何社交媒体网站或移动应用程序时,您无需在每次想要使用 Instagram 或 Facebook 时一次又一次地登录。相反,信息被保存,这意味着您不必在每次想要使用该网站时都登录。用技术术语来说,会话已经创建,它将在接下来的几天、几周或几个月内保持。
- Passport 还允许我们使用 Google、Facebook、LinkedIn 和各种其他社交网络服务轻松集成身份验证。
第七步:为了使用passport,我们需要安装4个npm包,分别是“ passport ”、“ passport-local ”、“ passport-local-mongoose ”和“ express-session ”(确保你下载了“express-session”而不是“快速会话”)。
在命令行中,编写以下命令来安装所有四个包:
npm install passport passport-local passport-local-mongoose express-session
安装后,您需要在Server.js文件的顶部添加以下代码以包含护照模块。
服务器.js
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
app.use(express.static("public"));
app.use(bodyParser.urlencoded({extended:true}));
// Below all the app.use methods
app.use(session({
secret : "any long secret key",
resave : false,
saveUninitialized : false
}));
第 8 步:初始化 Passport 并启动 Session。要初始化 Passport 并启动会话,请在会话声明代码下方编写以下代码。
服务器.js
app.use(session({
secret: "any long secret key",
resave: false,
saveUninitialized: false
}));
// Initializing Passport
app.use(passport.initialize());
// Starting the session
app.use(passport.session());
// Creating user schema and adding a plugin to it
const userSchema = new mongoose.Schema({
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
第 9 步:现在,我们希望即使关闭浏览器窗口也能保持登录状态一段时间,即我们希望建立会话。会话使用Cookie来存储数据和消息,并允许服务器向用户提供正确的会话数据。创建 Cookie 并将消息存储到其中的过程: 破碎 Cookie 并从 Cookie 中提取消息的序列化过程,以便向用户提供正确的数据:
服务器.js
const User = new mongoose.model("User", userSchema);
passport.use(User.createStrategy());
// Serializing and deserializing
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
第 10 步:现在,我们都准备好为我们的网站添加身份验证了。 我们已经安装了所需的包,配置了会话,初始化了 Passport 和会话,并告诉了 Passport 使用和管理 cookie。
处理获取请求:
服务器.js
// Handling get request on the home and login route
app.get("/", function (req, res) {
/* req.isAuthentcated() returns true or
false depending upon whether a session
is already running or not.*/
if(req.isAuthenticated()) {
/* if the request is already authenticated,
i.e. the user has already logged in and
there is no need to login again. Or we
can say, the session is running. */
res.send("
You have already logged in. No need to login again");
}
else{
// If the user is new and no session
// is Running already
res.sendFile(__dirname + "/index.html");
}
})
// Handling get request on login route
app.get("/login", function(req, res) {
if(req.isAuthenticated()){
/* if request is already authenticated,
i.e. user has already logged in and
there is no need to login again. */
res.send("
You have already logged in. No need to login again");
}
else{
res.sendFile(__dirname + "/login.html");
}
})
第 11 步:现在,在注册路线中,我们必须添加简单的代码,以便我们注册任何新用户。
服务器.js
/* The index.html file will be same as that
used in the earlier method of authentication*/
app.post("/register", function(req, res){
console.log(req.body);
// Getting Email and PAssword Entered by user
var email = req.body.username;
var password = req.body.password;
/* Registering the user with email and
password in our database
and the model used is "User" */
User.register({ username : email },
req.body.password, function (err, user) {
if (err) {
// if some error is occurring, log that error
console.log(err);
}
else {
passport.authenticate("local")
(req, res, function() {
res.send("successfully saved!");
})
}
})
})
类似的代码是处理登录请求。以下是处理 /login 路由上的 post 请求的代码。(login.html 文件将与之前的身份验证方法中使用的相同)
服务器.js
// All handling related to login is done below.
// Here we are handling the post request on
// /login route
app.post("/login", function (req, res) {
console.log(req.body);
const userToBeChecked = new User({
username: req.body.username,
password: req.body.password,
});
// Checking if user if correct or not
req.login(userToBeChecked, function (err) {
if (err) {
console.log(err);
// If authentication fails, then coming
// back to login.html page
res.redirect("/login");
} else {
passport.authenticate("local")(
req, res, function () {
User.find({ email: req.user.username },
function (err, docs) {
if (err) {
console.log(err);
} else {
//login is successful
console.log("credentials are correct");
res.send("login successful");
}
});
});
}
});
});
您只需要安装所有软件包,编写以下代码,启动服务器(使用“node server.js/node app.js”命令),您就可以使用 Passport 验证您的用户了。
索引.html
Page Title
REGISTER
登录.html
LOGIN
服务器.js
var express = require('express');
var app = express();
const mongoose = require("mongoose");
/* Requiring body-parser package
to fetch the data that is entered
by the user in the HTML form.*/
const bodyParser = require("body-parser");
// Telling our Node app to include all these modules
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose =
require("passport-local-mongoose");
// Allowing app to use body parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: "long secret key",
resave: false,
saveUninitialized: false
}));
// Initializing Passport
app.use(passport.initialize());
// Starting the session
app.use(passport.session());
// Connecting mongoose to our database
mongoose.connect(
'mongodb://localhost:27017/userDatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
/* Creating the schema of user which now
include only email and password for
simplicity.*/
const userSchema = new mongoose.Schema({
email: String,
password: String
});
/* Just after the creation of userSchema,
we add passportLocalMongoose plugin
to our Schema */
userSchema.plugin(passportLocalMongoose);
// Creating the User model
const User = new mongoose.model("User", userSchema);
/* After the creation of mongoose model,
we have to write the following code */
passport.use(User.createStrategy());
// Serializing and deserializing
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// Handling get request on the home route
app.get("/", function (req, res) {
/* req.isAuthentcated() returns true or
false depending upon whether a session is
already running or not. */
if (req.isAuthenticated()) {
/* if request is already authenticated,
i.e. user has already logged in and
there is no need to login again or
we can say, session is running.*/
res.send(
"You have already logged in. No need to login again");
}
else {
// If the user is new and
// no session is Running already
res.sendFile(__dirname + "/index.html");
}
})
// Handling get request on login route
app.get("/login", function (req, res) {
if (req.isAuthenticated()) {
/* If request is already authenticated,
i.e. user has already logged in and
there is no need to login again. */
res.send(
"You have already logged in. No need to login again");
}
else {
/* if session has expired, then user
need to login back again and
we will send the Login.html */
res.sendFile(__dirname + "/login.html");
}
})
/* Registering the user for the first time
handling the post request on /register route.*/
app.post("/register", function (req, res) {
console.log(req.body);
var email = req.body.username;
var password = req.body.password;
User.register({ username: email },
req.body.password, function (err, user) {
if (err) {
console.log(err);
}
else {
passport.authenticate("local")
(req, res, function () {
res.send("successfully saved!");
})
}
})
})
// Handling the post request on /login route
app.post("/login", function (req, res) {
console.log(req.body);
const userToBeChecked = new User({
username: req.body.username,
password: req.body.password
});
// Checking if user if correct or not
req.login(userToBeChecked, function (err) {
if (err) {
console.log(err);
res.redirect("/login");
}
else {
passport.authenticate("local")
(req, res,function () {
User.find({ email: req.user.username },
function (err, docs) {
if (err) {
console.log(err);
}
else {
//login is successful
console.log("credentials are correct");
res.send("login successful");
}
});
});
}
})
})
// Allowing app to listen on port 3000
app.listen(3000, function () {
console.log("server started successfully");
})
使用此代码并使用 Passport 添加身份验证,我们消除了三个主要问题:
- 一旦我们登录,就会创建一个会话。这意味着每当我们再次打开该站点时,我们都不需要再次登录。 Cookies 存储在浏览器中(当您第一次登录时),它们将在您再次访问时使用。 (req.isAuthenticated() 检查会话是否已经在运行)。
- 我们用户的密码是安全的。它们不会暴露在我们的数据库中。我们已将所有加密/解密任务委托给 Passport,仅此而已。
- 我们现在可以看到,没有“密码”列。我们的密码由 Passport 加密。并且每当需要它们进行登录时,Passport 都可以再次解密并使用它们。
- 我们还可以使用 Google、Facebook、LinkedIn 和仅使用 Passport 的各种其他社交网络服务添加身份验证。(我们在这里没有讨论,但代码与此类似)