如何在 Express.js 应用程序中实现 JWT 身份验证?
JSON 网络令牌
JSON Web 令牌 (JWT)是 JSON 对象,用于通过 Web 安全地传输信息(在两方之间)。它一般用于认证系统,也可用于信息交换。
这用于在 Internet 上通过加密传输数据,并且这些令牌可以通过使用附加签名来更加安全。这些令牌由标头 JSON 和有效负载 JSON 以及可选签名组成,三个中的每一个都与“.”连接,下面是 JSON Web 令牌的示例示例。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MTU0OWIwMTIwMWUyZjMzZWE3NmFkZjYiLCJlbWFpbCI6InNtdHdpbmtsZTQ1MkBnbWFpbC5jb20iLCJpYXQiOjE2MzI5MzQ2NTgsImV4cCI6MTYzMjkzODI1OH0._oHr3REme2pjDDdRliArAeVG_HuimbdM5suTw8HI7uc
JWT 身份验证的实现: JWT 在通过 HTTP 进行身份验证和授权方面非常流行。这些令牌可用作凭据以授予访问服务器资源的权限。
为什么我们需要在认证中使用 JWT:由于 HTTP 请求是无状态的,因此要知道当前请求与过去的请求相关是一项具有挑战性的任务。例如,登录后用户有权更改其数据,但在下一次请求时,服务器将如何识别它是先前请求登录的同一用户。为了解决这个挑战,我们使用 JWT。
在第一步中,服务器生成一个带有一些配置的令牌,例如有效负载、签名、到期等。下次当来自客户端的任何请求到达带有包含 JWT 令牌的授权标头时,服务器会解码该令牌并使用详细信息,并相应地允许访问。
示例:-让我们创建一个具有登录和注册功能的简单服务器。
第 1 步:初始化服务器并安装 JWT 包。
npm init
npm install jsonwebtoken
第 2 步:为令牌创建路由
解释:-
- 我们在第一行导入了 express、 mongoose和jsonwebtoken ,还导入了 User 模型,因为这是与数据库交互所必需的。在下一行中,我们调用了 express 方法,它返回一个应用程序,我们可以使用它来配置我们的服务器。我们在开始时使用 express.json 中间件,因为这样服务器可以将传入的请求识别为 JSON 对象。
- 之后,我们创建了两条路由,一条用于登录,另一条用于注册。
- 在 Login 路由中,我们从请求正文中提取了电子邮件和密码,然后在数据库中搜索用户,如果找到,我们将继续检查提供的密码是否与实际密码匹配。
- 在注册路由中,我们提取了姓名、电子邮件和密码等详细信息,以便在数据库中注册用户,使用mongoose提供的保存方法。
最后,我们通过提供有效负载作为用户 ID 和电子邮件创建了一个 1 小时到期的令牌,因为只有这样就足以提取用户信息。 sign 方法接受有效负载、秘密 jwt 密钥和到期时间,然后生成令牌。
文件名:app.js
Javascript
// Importing modules
const express = require("express");
const mongoose = require("mongoose");
const jwt = require("jsonwebtoken");
const User = require("./userModel");
const app = express();
app.use(express.json());
// Handling post request
app.post("/login", async (req, res, next) => {
let { email, password } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ email: email });
} catch {
const error = new Error("Error! Something went wrong.");
return next(error);
}
if (!existingUser || existingUser.password != password) {
const error = Error("Wrong details please check at once");
return next(error);
}
let token;
try {
//Creating jwt token
token = jwt.sign(
{ userId: existingUser.id, email: existingUser.email },
"secretkeyappearshere",
{ expiresIn: "1h" }
);
} catch (err) {
console.log(err);
const error = new Error("Error! Something went wrong.");
return next(error);
}
res
.status(200)
.json({
success: true,
data: {
userId: existingUser.id,
email: existingUser.email,
token: token,
},
});
});
// Handling post request
app.post("/signup", async (req, res, next) => {
const { name, email, password } = req.body;
const newUser = User({
name,
email,
password,
});
try {
await newUser.save();
} catch {
const error = new Error("Error! Something went wrong.");
return next(error);
}
let token;
try {
token = jwt.sign(
{ userId: newUser.id, email: newUser.email },
"secretkeyappearshere",
{ expiresIn: "1h" }
);
} catch (err) {
const error = new Error("Error! Something went wrong.");
return next(error);
}
res
.status(201)
.json({
success: true,
data: { userId: newUser.id,
email: newUser.email, token: token },
});
});
//Connecting to the database
mongoose
.connect("mongodb://localhost:27017/testDB")
.then(() => {
app.listen("3000", () => {
console.log("Server is listening on port 3000");
});
})
.catch((err) => {
console.log("Error Occured");
});
Javascript
app.get('/accessResource', (req, res)=>{
const token = req.headers.authorization.split(' ')[1];
//Authorization: 'Bearer TOKEN'
if(!token)
{
res.status(200).json({success:false, message: "Error!
Token was not provided."});
}
//Decoding the token
const decodedToken = jwt.verify(token,"secretkeyappearshere" );
res.status(200).json({success:true, data:{userId:decodedToken.userId,
email:decodedToken.email});
})
输出:我们正在使用 Postman 测试我们的 API,我们在请求正文中提供了用于注册的数据,最后,获得了带有其他详细信息的令牌。
第 3 步:解码 JWT 令牌
- 我们可以接收带有令牌的请求以授予权限,这里我们展示了一个如何解码令牌的简单示例。
- 令牌是通过请求头发送的,我们在这里从使用拆分函数的授权头中提取令牌,因为令牌保持“不记名令牌”的形式,我们只想提取令牌,这就是提供 1 索引的原因.
- verify 方法接受令牌和 jwt 密钥,并提供令牌的解码。之后,我们就可以得到用户的信息了。
Javascript
app.get('/accessResource', (req, res)=>{
const token = req.headers.authorization.split(' ')[1];
//Authorization: 'Bearer TOKEN'
if(!token)
{
res.status(200).json({success:false, message: "Error!
Token was not provided."});
}
//Decoding the token
const decodedToken = jwt.verify(token,"secretkeyappearshere" );
res.status(200).json({success:true, data:{userId:decodedToken.userId,
email:decodedToken.email});
})
输出:这里我们正在测试负责接受令牌的 API,我们在标头中传递了令牌,最后服务器成功解码用户详细信息。
结论:至此,我们成功实现了token从创建到解码的整个过程。 ' accessResource ' 路由的这个示例足以说明其工作原理,您可以在内部以您想要的方式使用您的令牌,并可以相应地允许用户。这一切都意味着我们能够成功地持久化无状态 HTTP 请求的信息。