在 Node.js 中实现身份验证与授权

在 Node.js 中实现身份验证与授权

在现代Web应用中,身份验证和授权扮演着至关重要的角色。实现一个安全的身份验证和授权机制既能保护用户的数据安全,又能提高用户体验。在本文中,我们将使用 Node.js 来实现简单的身份验证与授权,特别是使用 JSON Web Token (JWT)。

什么是身份验证与授权?

  • 身份验证是验证用户身份的过程,确保用户是他们所声称的那个人。
  • 授权是在身份验证之后,确定用户对某些资源的访问权限。

接下来,我们将通过实现一个简单的用户注册、登录和基于JWT的授权系统来展示如何在 Node.js 中完成这些过程。

环境准备

在开始之前,确保你已经安装了 Node.js 和 npm。然后,你可以使用以下步骤来初始化一个新的 Node.js 项目:

mkdir node-auth-example
cd node-auth-example
npm init -y

接下来,安装所需的依赖项:

npm install express mongoose bcrypt jsonwebtoken dotenv
  • express:我们将要使用的 web 框架。
  • mongoose:MongoDB ODM,用于处理 MongoDB 数据库。
  • bcrypt:用于 hashing 用户密码。
  • jsonwebtoken:用于生成和验证 JWT。
  • dotenv:用于加载环境变量。

创建基本的项目结构

创建一个 server.js 文件作为我们的应用入口,并创建一个 models 目录来存放用户模型。

touch server.js
mkdir models
touch models/User.js

定义用户模型

models/User.js 文件中,我们将定义用户模型。这里我们使用 Mongoose 来创建一个用户的Schema。

// models/User.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
    username: { 
        type: String, 
        required: true, 
        unique: true 
    },
    password: { 
        type: String, 
        required: true 
    }
});

const User = mongoose.model('User', userSchema);
module.exports = User;

实现注册与登录功能

server.js 中,首先设置 Express 应用:

// server.js
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('./models/User');
require('dotenv').config();

const app = express();
app.use(express.json());

mongoose.connect('mongodb://localhost:27017/auth-example', { 
    useNewUrlParser: true, 
    useUnifiedTopology: true 
})
.then(() => console.log('MongoDB connected'))
.catch(err => console.log(err));

// 用户注册
app.post('/register', async (req, res) => {
    const { username, password } = req.body;

    // 检查用户是否已经存在
    const existingUser = await User.findOne({ username });
    (existingUser) {
        return res.status(400).send('User already exists');
    }

    // 哈希密码
    const hashedPassword = await bcrypt.hash(password, 10);

    // 创建新用户
    const user = new User({
        username,
        password: hashedPassword
    });

    await user.save();
    res.send('User registered successfully');
});

// 用户登录
app.post('/login', async (req, res) => {
    const { username, password } = req.body;

    // 查找用户
    const user = await User.findOne({ username });
    if (!user) {
        return res.status(400).send('Invalid credentials');
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
        return res.status(400).send('Invalid credentials');
    }

    // 生成JWT
    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
    res.json({ token });
});

实现授权中间件

接下来,我们需要一个中间件来验证每个请求中的 JWT,并确保用户已通过身份验证。

// middleware/auth.js
const jwt = require('jsonwebtoken');

function authenticateToken(req, res, next) {
    const token = req.headers['authorization']?.split(' ')[1];
    if (!token) return res.sendStatus(403);

    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
    });
}

module.exports = authenticateToken;

保护路由

现在,我们可以使用我们创建的 authenticateToken 中间件来保护某些路由,仅允许经过身份验证的用户访问这些路径。

// 受保护的路由
app.get('/protected', authenticateToken, (req, res) => {
    res.send(`Welcome user with ID: ${req.user.id}`);
});

完整代码

确保你的 server.js 文件看起来像这样:

const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('./models/User');
const authenticateToken = require('./middleware/auth');
require('dotenv').config();

const app = express();
app.use(express.json());

mongoose.connect('mongodb://localhost:27017/auth-example', { 
    useNewUrlParser: true, 
    useUnifiedTopology: true 
})
.then(() => console.log('MongoDB connected'))
.catch(err => console.log(err));

// 用户注册
app.post('/register', async (req, res) => {
    const { username, password } = req.body;
    const existingUser = await User.findOne({ username });
    if (existingUser) {
        return res.status(400).send('User already exists');
    }
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, password: hashedPassword });
    await user.save();
    res.send('User registered successfully');
});

// 用户登录
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    const user = await User.findOne({ username });
    if (!user) {
        return res.status(400).send('Invalid credentials');
    }
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
        return res.status(400).send('Invalid credentials');
    }
    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
    res.json({ token });
});

// 受保护的路由
app.get('/protected', authenticateToken, (req, res) => {
    res.send(`Welcome user with ID: ${req.user.id}`);
});

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

运行应用

为了运行你的 Node.js 应用程序,确保设置了一个 JWT_SECRET.env 文件中:

JWT_SECRET=yoursecretkey

然后,你可以运行你的应用程序:

node server.js

你可以使用 Postman 或任何其他 API 测试工具来测试注册、登录和访问受保护的路由。

结语

通过以上步骤,我们实现了一个基本的身份验证与授权机制。尽管这个例子相对简单,但它为你提供了一个良好的基础,你可以在此基础上构建更复杂的系统。在实际应用中,你可能还需要考虑其他安全性因素,比如加密存储、HTTPS、刷新 token 等等。


最后问候亲爱的朋友们,并邀请你们阅读我的全新著作

在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JJCTO袁龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值