Node.js 编程实战:博客系统 —— 用户注册登录与文章管理

在上一篇文章中,我们完成了博客系统的 需求分析数据库设计 。有了清晰的模型和数据表结构,接下来就是将这些功能落地,开始开发核心业务模块------用户注册登录与文章管理

本文将详细介绍如何使用 Node.js + Express + Sequelize / Mongoose 搭建用户认证和文章管理接口,实现前后端可交互的基础功能。


一、用户注册与登录模块

用户模块是博客系统的基础模块,涉及注册、登录、鉴权和权限控制。


1. 用户注册

用户注册流程:

  1. 前端提交用户名、邮箱和密码
  2. 后端验证数据合法性(必填、邮箱格式、密码强度)
  3. 密码加密(推荐 bcrypt)
  4. 写入数据库

示例代码(使用 bcrypt 和 Sequelize):

js 复制代码
const bcrypt = require('bcrypt');
const { User } = require('../models');

async function register(req, res) {
  const { username, email, password } = req.body;
  
  if (!username || !email || !password) {
    return res.status(400).json({ message: '必填字段缺失' });
  }

  const hash = await bcrypt.hash(password, 10);

  const user = await User.create({ username, email, password: hash });
  res.status(201).json({ message: '注册成功', userId: user.id });
}

2. 用户登录

用户登录流程:

  1. 前端提交邮箱/用户名和密码
  2. 后端查询数据库,验证密码
  3. 生成 JWT Token 返回给前端
  4. 后续请求带上 Token,进行权限验证

示例代码:

js 复制代码
const jwt = require('jsonwebtoken');

async function login(req, res) {
  const { email, password } = req.body;
  const user = await User.findOne({ where: { email } });
  
  if (!user) return res.status(404).json({ message: '用户不存在' });

  const valid = await bcrypt.compare(password, user.password);
  if (!valid) return res.status(401).json({ message: '密码错误' });

  const token = jwt.sign({ id: user.id, role: user.role }, 'secretKey', { expiresIn: '1h' });
  res.json({ message: '登录成功', token });
}

3. JWT 鉴权中间件

为了保护需要登录的接口,可以使用中间件验证 JWT:

js 复制代码
const jwt = require('jsonwebtoken');

function authMiddleware(req, res, next) {
  const token = req.headers['authorization']?.split(' ')[1];
  if (!token) return res.status(401).json({ message: '未授权' });

  try {
    const decoded = jwt.verify(token, 'secretKey');
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ message: 'Token无效' });
  }
}

二、文章管理模块

文章模块是博客系统的核心业务,主要涉及 文章增删改查


1. 发布文章

管理员或登录用户可以发布文章:

js 复制代码
async function createArticle(req, res) {
  const { title, content, categoryId, tags } = req.body;
  
  const article = await Article.create({
    title,
    content,
    author_id: req.user.id,
    category_id: categoryId
  });

  // 可选:关联标签
  if (tags && tags.length > 0) {
    await article.addTags(tags); // Sequelize 多对多关系
  }

  res.status(201).json({ message: '文章发布成功', articleId: article.id });
}

2. 编辑文章

用户可以编辑自己发布的文章,管理员可以编辑所有文章:

js 复制代码
async function updateArticle(req, res) {
  const { id } = req.params;
  const { title, content, categoryId } = req.body;

  const article = await Article.findByPk(id);
  if (!article) return res.status(404).json({ message: '文章不存在' });

  if (req.user.role !== 'admin' && article.author_id !== req.user.id) {
    return res.status(403).json({ message: '无权限编辑该文章' });
  }

  article.title = title || article.title;
  article.content = content || article.content;
  article.category_id = categoryId || article.category_id;

  await article.save();
  res.json({ message: '文章更新成功' });
}

3. 删除文章

删除文章也需做权限检查:

js 复制代码
async function deleteArticle(req, res) {
  const { id } = req.params;

  const article = await Article.findByPk(id);
  if (!article) return res.status(404).json({ message: '文章不存在' });

  if (req.user.role !== 'admin' && article.author_id !== req.user.id) {
    return res.status(403).json({ message: '无权限删除该文章' });
  }

  await article.destroy();
  res.json({ message: '文章删除成功' });
}

4. 获取文章列表与详情

文章列表接口可以支持分页、筛选和排序:

js 复制代码
async function listArticles(req, res) {
  const { page = 1, pageSize = 10, categoryId } = req.query;

  const where = {};
  if (categoryId) where.category_id = categoryId;

  const articles = await Article.findAndCountAll({
    where,
    order: [['created_at', 'DESC']],
    offset: (page - 1) * pageSize,
    limit: parseInt(pageSize)
  });

  res.json({ total: articles.count, data: articles.rows });
}

async function getArticleDetail(req, res) {
  const { id } = req.params;
  const article = await Article.findByPk(id, { include: ['author', 'tags'] });
  if (!article) return res.status(404).json({ message: '文章不存在' });
  res.json(article);
}

三、接口安全与最佳实践

  • 对敏感接口(发布、编辑、删除)使用 JWT 鉴权
  • 对用户操作记录日志,便于追踪问题
  • 对文章内容可做 XSS 过滤
  • 分页接口防止一次性查询过多数据

这些措施能有效提升系统安全性和稳定性。


四、总结

用户注册登录和文章管理是博客系统的核心功能模块。通过合理设计接口、权限控制和数据模型,我们可以实现一个基础可用、可扩展的后端服务。

相关推荐
xkxnq2 小时前
第二阶段:Vue 组件化开发(第 23天)
前端·javascript·vue.js
zcz16071278212 小时前
nmcli常见操作
前端·chrome
晴栀ay2 小时前
JS的超集——TypeScript
前端·react.js·typescript
掘金者阿豪2 小时前
在Java项目中,如果没有使用Redis相关的代码或依赖,但在 `application.yaml` 配置文件中配置了Redis参数,项目启动时是否会报错
后端
EndingCoder2 小时前
高级类型:联合类型和类型别名
linux·服务器·前端·ubuntu·typescript
几颗流星2 小时前
使用 Rust + Axum 构建灵活的 API 模拟服务器
后端·rust
小杨同学492 小时前
【嵌入式 C 语言实战】单链表的完整实现与核心操作详解
后端·算法·架构
咋吃都不胖lyh2 小时前
RESTful API 调用详解(零基础友好版)
后端·restful