在上一篇文章中,我们完成了博客系统的 需求分析 和数据库设计 。有了清晰的模型和数据表结构,接下来就是将这些功能落地,开始开发核心业务模块------用户注册登录与文章管理。
本文将详细介绍如何使用 Node.js + Express + Sequelize / Mongoose 搭建用户认证和文章管理接口,实现前后端可交互的基础功能。
一、用户注册与登录模块
用户模块是博客系统的基础模块,涉及注册、登录、鉴权和权限控制。
1. 用户注册
用户注册流程:
- 前端提交用户名、邮箱和密码
- 后端验证数据合法性(必填、邮箱格式、密码强度)
- 密码加密(推荐 bcrypt)
- 写入数据库
示例代码(使用 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. 用户登录
用户登录流程:
- 前端提交邮箱/用户名和密码
- 后端查询数据库,验证密码
- 生成 JWT Token 返回给前端
- 后续请求带上 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 过滤
- 分页接口防止一次性查询过多数据
这些措施能有效提升系统安全性和稳定性。
四、总结
用户注册登录和文章管理是博客系统的核心功能模块。通过合理设计接口、权限控制和数据模型,我们可以实现一个基础可用、可扩展的后端服务。