Node.js API 使用 JWT(Json Web Token)进行身份验证 - Auth 中间件

2025-06-07

Node.js API 使用 JWT(Json Web Token)进行身份验证 - Auth 中间件

大家好,今天我们将在 Node.js 应用程序中使用JWT实现API身份验证。身份验证是每个应用程序中最重要的功能。即使您是初学者,也可以尝试本教程,我们将从零开始。我们还将编写Auth中间件,仅允许经过身份验证的用户访问路由。

在 React 中使用 JWT(Json Web Token)进行身份验证

为了更好地理解,请观看演示视频


源代码

让我们开始编码...

应用程序概述:

项目结构 下表显示了导出的 Rest API 的概述:
项目结构

方法 网址 行动
邮政 /api/用户 创建用户
邮政 /api/授权 验证用户
得到 /api/用户/我 获取已验证用户的详细信息

创建 Node.js 应用程序并安装依赖项

$    mkdir node-auth-jwt
$    cd node-auth-jwt
$    npm init --yes
$    npm install express mongoose jsonwebtoken bcrypt joi dotenv
Enter fullscreen mode Exit fullscreen mode

express: Express 是最小且灵活的 Node.js Web 应用程序框架。mongoose
Mongoose 是 MongoDB 和 Node.js 的对象数据建模(ODM)库
。jsonwebtoken:它是一个表示要在双方之间转移的声明的紧凑 URL。bcrypt
它是一个密码哈希函数。joi
Joi 是一种对象模式描述语言和 JavaScript 对象的验证器。dotenv
它从 .env 文件加载环境变量。

设置 Express Web 服务器
/index.js

require("dotenv").config();
const express = require("express");
const app = express();

app.use(express.json());

const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on port ${port}...`));
Enter fullscreen mode Exit fullscreen mode

配置环境变量
/.env

DB = "mongodb://localhost/node-auth-api/"
JWTPRIVATEKEY = "secretkey"
SALT = 10
Enter fullscreen mode Exit fullscreen mode

配置 MongoDB 数据库
/db.js

const mongoose = require("mongoose");

module.exports = async () => {
    try {
        const connectionParams = {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true,
        };
        await mongoose.connect(process.env.DB, connectionParams);
        console.log("connected to database.");
    } catch (error) {
        console.log("could not connect to database", error);
    }
};
Enter fullscreen mode Exit fullscreen mode

index.js中导入db.js并调用

//...
const connection = require("./db");
const express = require("express");
const app = express();

connection();
app.use(express.json());
//...
Enter fullscreen mode Exit fullscreen mode

创建用户模型
/models/user.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const jwt = require("jsonwebtoken");
const Joi = require("joi");

const userSchema = new Schema({
    name: {
        type: String,
        required: true,
    },
    email: {
        type: String,
        required: true,
    },
    password: {
        type: String,
        required: true,
    },
});

userSchema.methods.generateAuthToken = function () {
    const token = jwt.sign({ _id: this._id }, process.env.JWTPRIVATEKEY);
    return token;
};

const User = mongoose.model("user", userSchema);

const validate = (user) => {
    const schema = Joi.object({
        name: Joi.string().required(),
        email: Joi.string().email().required(),
        password: Joi.string().required(),
    });
    return schema.validate(user);
};

module.exports = { User, validate };
Enter fullscreen mode Exit fullscreen mode

我们所做的:

  • 我们创建了包含姓名、电子邮件和密码的用户表。
  • 使用JWT,我们生成带有用户 ID 有效负载的令牌。
  • 使用Joi,我们将验证数据。

注册路由
/routes/users.js

const { User, validate } = require("../models/user");
const bcrypt = require("bcrypt");
const express = require("express");
const router = express.Router();

router.post("/", async (req, res) => {
    try {
        const { error } = validate(req.body);
        if (error) return res.status(400).send(error.details[0].message);

        const user = new User(req.body);

        const salt = await bcrypt.genSalt(Number(process.env.SALT));
        user.password = await bcrypt.hash(user.password, salt);
        await user.save();

        res.send(user);
    } catch (error) {
        console.log(error);
        res.send("An error occured");
    }
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

登录路由
/routes/auth.js

const { User } = require("../models/user");
const bcrypt = require("bcrypt");
const Joi = require("joi");
const express = require("express");
const router = express.Router();

router.post("/", async (req, res) => {
    try {
        const { error } = validate(req.body);
        if (error) return res.status(400).send(error.details[0].message);

        const user = await User.findOne({ email: req.body.email });
        if (!user) return res.status(400).send("Invalid email or password");

        const validPassword = await bcrypt.compare(
            req.body.password,
            user.password
        );
        if (!validPassword)
            return res.status(400).send("Invalid email or password");

        const token = user.generateAuthToken();
        res.send(token);
    } catch (error) {
        console.log(error);
        res.send("An error occured");
    }
});

const validate = (user) => {
    const schema = Joi.object({
        email: Joi.string().email().required(),
        password: Joi.string().required(),
    });
    return schema.validate(user);
};

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

身份验证中间件
/middleware/auth.js

const jwt = require("jsonwebtoken");

module.exports = (req, res, next) => {
    try {
        const token = req.header("x-auth-token");
        if (!token) return res.status(403).send("Access denied.");

        const decoded = jwt.verify(token, process.env.JWTPRIVATEKEY);
        req.user = decoded;
        next();
    } catch (error) {
        res.status(400).send("Invalid token");
    }
};
Enter fullscreen mode Exit fullscreen mode

用户获取路线
/routes/users.js

const auth = require("../middleware/auth");
//...

router.get("/me", auth, async (req, res) => {
    try {
        const user = await User.findById(req.user._id).select("-password -__v");
        res.send(user);
    } catch (error) {
        console.log(error);
        res.send("An error occured");
    }
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

在 Index.js 中导入路由

//...
const users = require("./routes/users");
const auth = require("./routes/auth");
//...

app.use(express.json());

app.use("/api/users", users);
app.use("/api/auth", auth);

//...
Enter fullscreen mode Exit fullscreen mode

就这样!运行服务器并测试 API。如果您发现任何错误或需要改进代码,请在评论中告诉我。希望您有所收获。

谢谢...

文章来源:https://dev.to/mrcyberwolf/node-js-api-authentication-with-jwt-json-web-token-auth-middleware-ggm
PREV
使用 ESBuild 的 React+Typescript 应用程序
NEXT
70 多个 Python 项目(含源代码):从初学者到高级