如何在Node.js+Express+MongoDB博客应用中实现管理员审核发布系统及管理面板
Great question! Let's break this down step by step—we'll start with foundational database changes, then add admin authentication, build backend routes, create the frontend panel, and update your existing blog logic.
1. Update Database Schemas
First, we need to adjust your existing schemas to support moderation states and admin roles.
Modify the User Schema
Add an isAdmin boolean field to mark users as admins (defaults to false for regular users):
// models/User.js const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true }, isAdmin: { type: Boolean, default: false } // New admin flag // ... your existing user fields }); module.exports = mongoose.model('User', userSchema);
Modify the Post Schema
Add a status field to track moderation state, and ensure we're linking posts to their authors clearly:
// models/Post.js const mongoose = require('mongoose'); const postSchema = new mongoose.Schema({ title: { type: String, required: true }, content: { type: String, required: true }, authorId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, username: { type: String, required: true }, // Store username for quick access status: { type: String, enum: ['pending', 'approved', 'rejected'], default: 'pending' // New posts start as pending approval }, createdAt: { type: Date, default: Date.now } // ... your existing post fields }); module.exports = mongoose.model('Post', postSchema);
Note: Storing username directly in the Post schema saves you from populating the User reference every time you need it, but you can also populate the author field if you prefer more flexibility.
2. Create Admin Authentication Middleware
This middleware will protect your admin routes—only users with isAdmin: true can access the panel:
// middleware/adminAuth.js module.exports = (req, res, next) => { // Assuming your login system sets req.user (e.g., via sessions or Passport) if (!req.user || !req.user.isAdmin) { return res.status(403).send('Access denied. Admin privileges required.'); // Or redirect to login: return res.redirect('/login'); } next(); };
3. Build Admin Backend Routes
Add these routes to handle admin actions like viewing posts and approving/rejecting content:
// routes/admin.js const express = require('express'); const router = express.Router(); const adminAuth = require('../middleware/adminAuth'); const Post = require('../models/Post'); // Admin Dashboard: Show all posts sorted by creation date router.get('/dashboard', adminAuth, async (req, res) => { try { const posts = await Post.find() .sort({ createdAt: -1 }) .select('_id title username status createdAt'); // Fetch only necessary fields res.render('admin/dashboard', { posts }); // Render the admin template } catch (err) { console.error(err); res.status(500).send('Server error loading dashboard'); } }); // Approve a post router.post('/posts/:id/approve', adminAuth, async (req, res) => { try { await Post.findByIdAndUpdate(req.params.id, { status: 'approved' }); res.redirect('/admin/dashboard'); // Redirect back to dashboard } catch (err) { console.error(err); res.status(500).send('Failed to approve post'); } }); // Reject a post router.post('/posts/:id/reject', adminAuth, async (req, res) => { try { await Post.findByIdAndUpdate(req.params.id, { status: 'rejected' }); res.redirect('/admin/dashboard'); } catch (err) { console.error(err); res.status(500).send('Failed to reject post'); } }); module.exports = router;
Register these routes in your main app file:
// app.js const adminRoutes = require('./routes/admin'); app.use('/admin', adminRoutes);
4. Create the Admin Panel Frontend
We'll use EJS (a popular templating engine for Express) to build a simple, functional dashboard. First, confirm EJS is set up:
// app.js app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views'));
Then create the dashboard template:
<!-- views/admin/dashboard.ejs --> <!DOCTYPE html> <html> <head> <title>Blog Admin Dashboard</title> <style> .post-card { border: 1px solid #ddd; padding: 15px; margin: 10px 0; border-radius: 5px; } .pending { border-left: 4px solid #ffc107; } .approved { border-left: 4px solid #28a745; } .rejected { border-left: 4px solid #dc3545; } button { padding: 6px 12px; margin-right: 8px; border: none; border-radius: 3px; cursor: pointer; } .approve-btn { background-color: #28a745; color: white; } .reject-btn { background-color: #dc3545; color: white; } </style> </head> <body> <h1>Post Moderation Dashboard</h1> <% posts.forEach(post => { %> <div class="post-card <%= post.status %>"> <h3><%= post.title %></h3> <p><strong>Author:</strong> <%= post.username %> (User ID: <%= post.authorId %>)</p> <p><strong>Status:</strong> <%= post.status.charAt(0).toUpperCase() + post.status.slice(1) %></p> <p><strong>Created:</strong> <%= new Date(post.createdAt).toLocaleString() %></p> <% if (post.status === 'pending') { %> <form action="/admin/posts/<%= post._id %>/approve" method="POST" style="display: inline;"> <button type="submit" class="approve-btn">Approve</button> </form> <form action="/admin/posts/<%= post._id %>/reject" method="POST" style="display: inline;"> <button type="submit" class="reject-btn">Reject</button> </form> <% } %> </div> <% }) %> </body> </html>
This template displays all posts with their details, and only shows approve/reject buttons for pending content.
5. Update Public Blog Routes
Ensure your public blog only displays approved posts:
// routes/blog.js router.get('/', async (req, res) => { try { const approvedPosts = await Post.find({ status: 'approved' }) .sort({ createdAt: -1 }); res.render('blog/index', { posts: approvedPosts }); } catch (err) { console.error(err); res.status(500).send('Server error loading blog'); } });
6. Create an Admin User (For Testing)
To test the panel, create an admin user with a seed script:
// scripts/seedAdmin.js const mongoose = require('mongoose'); const User = require('../models/User'); const bcrypt = require('bcryptjs'); // Assuming you use bcrypt for password hashing mongoose.connect('your-mongodb-uri') .then(async () => { const hashedPassword = await bcrypt.hash('your-strong-admin-password', 10); const adminUser = new User({ username: 'admin', email: 'admin@yourblog.com', password: hashedPassword, isAdmin: true }); await adminUser.save(); console.log('Admin user created successfully'); process.exit(); }) .catch(err => { console.error(err); process.exit(1); });
Run this script once to set up your admin account.
Final Tips
- Security: Use HTTPS in production, enforce strong admin passwords, and consider adding two-factor authentication for admin accounts.
- Enhancements: You could add features like viewing full post content in the dashboard, sending email notifications to users when their post is reviewed, or adding a rejection reason field.
- Dynamic Frontend: If you want a more interactive panel, build it with React/Vue and use Express API endpoints instead of server-rendered EJS.
内容的提问来源于stack exchange,提问作者techy_sagar

