You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:40:25