使用 NodeJS 进行用户身份验证和授权的不同方法(第一部分)
基于会话的身份验证
首先让我们解决身份验证与授权的争论。
验证
这是验证用户是否说实话的过程。例如:当我们使用用户名和密码登录账户时,我们会根据数据库中存储的信息验证这些凭证,并确认用户是否是其本人,这个过程称为身份验证。
授权
了解用户有权访问哪些信息是一个安全过程。授权的典型例子包括授予某人下载服务器上特定文件的权限,或授予单个用户对应用程序的管理权限。
在本文中,我们将研究使用 NodeJS 进行用户身份验证的两种不同方法
- 基于会话的身份验证
- 基于令牌的身份验证
先决条件
npm
使用或任何你喜欢的方式设置一个新的 NodeJS 项目yarn
。
基于会话的身份验证
这张图非常简单地概括了基于会话的身份验证。让我们用代码来实现它,以便更好地理解。
在项目目录中的终端上执行以下代码行。
npm install express express-session mongoose connect-mongo
express - 用于创建我们的服务器
express-session - 用于创建基于会话的身份验证
mongoose - 连接到我们的 MongoDB 数据库
connect-mongo - 用于将我们的会话存储在 MongoDB 数据库中
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo');
const session = require('express-session');
await mongoose.connect('your_mongo_url', (err, db) => {
console.log('MongoDB Connected....');
});
app.get('/', (req,res)=>{
res.send('<h1>Hello World!</h1>')
})
app.listen(5000, () => console.log(`Server 🔥🔥🔥 up on 5000`));
这段代码将使我们的服务器在端口 5000 上启动并运行。因此,如果您现在访问http://localhost:5000/,您将看到所需的结果。
现在让我们配置 MongoDB 存储以进行会话存储。
app.use(session({
secret: 'fiwafhiwfwhvuwvu9hvvvwv', // Never ever share this secret in production, keep this in separate file on environmental variable
resave: false,
saveUninitialized: true,
cookie: { maxAge: oneDay },
store: MongoStore.create({
mongoUrl: 'your_mongo_url'
})
}));
这段代码使用了 express-session 包来为请求创建一个空的 Session 对象。
请参阅此链接,了解该对象中的 saveUninitialized 和 resave 属性。
因此,这将在我们的 mongodb 数据库中创建一个新的空会话,其集合名称为 session。
让我们为用户创建一个登录路由
app.post('/login', async (req, res) => {
const { username, password } = req.body;
try {
let user = await User.findOne({ email: username })
req.session.userId = user.id;
console.log(req.session);
res.redirect('/dashboard')
} catch (err) {
console.log(err);
res.json({ msg: 'Server Error! Please reload page' });
}
})
现在这部分代码很重要。现在,当用户使用用户名和密码登录其帐户时,我们会将该请求发送到服务器,并将其存储在会话中。req.session.userId
会话中存储用户的唯一 _id,服务器会创建一个唯一的会话 ID,并将其放入 Cookie 中,该 Cookie 将被发送回客户端并存储在客户端浏览器中。现在,每当客户端向服务器发出任何请求时,请求头都会包含此 Cookie,我们在服务器端可以使用请求头中的 Cookie 并获取用户的 userId 来验证该特定用户的身份。
module.exports.authentication = async (req, res, next) => {
const userId = req.session.userId;
if (!userId) {
return res.redirect('/login?q=session-expired');
}
try {
let user = await User.findById(userId);
if (!user) {
return res.redirect('/login?q=session-expired');
}
next();
} catch (err) {
console.log(err);
res.json({ msg: 'Server error. Please reload page after sometime' })
}
};
我们可以创建这种类型的中间件功能,对于受保护路线(如仪表板、预订历史记录、付款路线等)上的每个请求,我们都可以验证用户并根据用户显示正确的数据。
基于会话的身份验证的优势
- Cookies 是小尺寸的值,易于使用和实现,并且可以撤销 cookies 的有效性。
基于会话的身份验证的缺点
- 会话存储在服务器/数据库中而不是客户端,因此当同时有大量请求时,项目扩展变得非常困难。
这时,基于令牌的身份验证(一种现代且可扩展的解决方案)就派上用场了。它解决了会话身份验证中最大的难题——令牌存储在客户端浏览器中,从而让应用程序的扩展变得非常简单。
敬请期待第二部分,我们将在其中详细讨论基于令牌的身份验证。