Node.js中JWT验证路由通过后如何用Handlebars渲染页面?
Hey there! Let's get your authenticated routes rendering Handlebars pages after login sorted out. Based on the code snippets you shared, here's a practical, step-by-step implementation:
1. First, Double-Check Your Handlebars Setup
Make sure your Express app is properly configured to use Handlebars. If you haven't already, install the required package and set up the view engine:
npm install express-handlebars cookie-parser
Then in your main app file (like app.js):
const express = require('express'); const path = require('path'); const exphbs = require('express-handlebars'); const cookieParser = require('cookie-parser'); const app = express(); // Configure Handlebars as the view engine app.engine('hbs', exphbs({ extname: 'hbs' })); app.set('view engine', 'hbs'); app.set('views', path.join(__dirname, 'views')); // Point to your templates folder // Middleware to parse form data and cookies app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(cookieParser()); // Required to read JWT stored in cookies
2. Fix Your Route Order (Critical!)
Right now, your global app.use(ctrlUsers.authenticate) middleware will block the login route too. Move the login route before this global middleware so users can actually access the login page:
// index.js (routes) const ctrlUsers = require('../controllers/users.controllers.js'); // Public login route (must come before auth middleware) router.route('/users/login') .get((req, res) => res.render('login')) // Render login form .post(ctrlUsers.login); // Apply auth middleware to all subsequent routes app.use(ctrlUsers.authenticate); // Authenticated route that renders a Handlebars page router.get('/dashboard', (req, res) => { // Pass the logged-in user's data to the template res.render('dashboard', { user: req.user }); }); app.use('/', router);
3. Update the Login Controller for Server-Rendered Flow
Instead of returning JWT as JSON (which works for Postman), store the token in an HttpOnly cookie. This lets the browser automatically send the token with every request, perfect for server-rendered pages:
// users.controllers.js const jwt = require('jsonwebtoken'); const User = require('../models/User'); // Assume you have a User model exports.login = async (req, res) => { try { const { username, password } = req.body; // Validate user credentials (adjust to match your User model logic) const user = await User.findOne({ username }); if (!user || !(await user.comparePassword(password))) { return res.render('login', { error: 'Invalid username or password' }); } // Generate JWT token const token = jwt.sign( { id: user._id, username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' } ); // Store token in a secure HttpOnly cookie res.cookie('token', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // Use HTTPS in production maxAge: 3600000 // Expire after 1 hour }); // Redirect to the authenticated dashboard after successful login res.redirect('/dashboard'); } catch (err) { res.render('login', { error: 'Server error. Please try again.' }); } };
4. Refine the Authenticate Middleware
Update your auth middleware to read the JWT from the cookie, validate it, and attach user data to the request object (so Handlebars can access it):
// users.controllers.js exports.authenticate = (req, res, next) => { // Get token from cookie (fallback to Authorization header for Postman testing) const token = req.cookies.token || req.headers.authorization?.split(' ')[1]; if (!token) { // No token found: redirect to login return res.redirect('/users/login'); } try { // Verify the JWT token const decoded = jwt.verify(token, process.env.JWT_SECRET); // Attach user data to req.user for use in routes and templates req.user = decoded; next(); // Proceed to the authenticated route } catch (err) { // Invalid token: clear cookie and redirect to login res.clearCookie('token'); res.redirect('/users/login?error=InvalidSession'); } };
5. Create Your Handlebars Templates
Add these templates to your views directory:
views/login.hbs
<!DOCTYPE html> <html> <head> <title>Login</title> </head> <body> <h2>Login to Your Account</h2> {{#if error}} <p style="color: red;">{{error}}</p> {{/if}} <form method="POST" action="/users/login"> <div> <label>Username:</label> <input type="text" name="username" required> </div> <div> <label>Password:</label> <input type="password" name="password" required> </div> <button type="submit">Log In</button> </form> </body> </html>
views/dashboard.hbs
<!DOCTYPE html> <html> <head> <title>Your Dashboard</title> </head> <body> <h1>Welcome back, {{user.username}}!</h1> <p>This is your authenticated dashboard — only logged-in users can access this page.</p> <a href="/logout">Log Out</a> </body> </html>
6. Add a Logout Route
Let users log out by clearing the auth cookie:
// index.js (routes) router.get('/logout', (req, res) => { res.clearCookie('token'); res.redirect('/users/login'); });
Key Takeaways
- Route Order: Always place public routes (like login) before global auth middleware to avoid blocking them.
- HttpOnly Cookies: These are more secure than storing JWT in localStorage, as they can't be accessed by JavaScript (preventing XSS attacks).
- User Data in Templates: By attaching
req.user, you can directly access user details in your Handlebars files. - Error Feedback: We added error messages to the login template to give users clear feedback on failed attempts.
内容的提问来源于stack exchange,提问作者Manu Jha

