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

基于Vanilla Node.js实现会话序列化登录模块的技术问询

Hey there! Your initial plan for building a login system with session serialization using vanilla Node.js is totally on the right path—let’s tackle that cookie consistency issue and walk through a complete, working implementation step by step.

Vanilla Node.js Session Serialized Login System

First, let’s fix the core problem you ran into: cookie inconsistency across routes. This happens because by default, cookies are tied to the specific route they’re set from (e.g., a cookie set at /login only works for /login and its subroutes). The fix is simple: explicitly set the cookie’s path=/ so it’s accessible across your entire app.

Full Implementation Breakdown

1. Base Setup: HTTP Server & Mock Databases

We’ll use Node’s native http module for the server, and in-memory maps to simulate user and session storage (swap these with real databases like SQLite/MySQL using their native drivers in production):

const http = require('http');
const crypto = require('crypto'); // For secure session ID generation

// Mock user database (store hashed passwords, NEVER plaintext!)
const users = new Map([
  ['jane@example.com', { id: 1, password: '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8' }], // SHA256 hash of "password123"
  ['john@example.com', { id: 2, password: '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8' }]
]);

// Mock session store (maps session ID -> user ID)
const sessions = new Map();

2. Validate User Credentials

Always hash passwords (never store plaintext!). Here’s a basic validation function using SHA256 (use crypto.pbkdf2 or crypto.scrypt with a salt in production for better security):

function validateUser(email, password) {
  const user = users.get(email);
  if (!user) return null;

  // Hash input password to compare with stored hash
  const inputHash = crypto.createHash('sha256').update(password).digest('hex');
  return inputHash === user.password ? user : null;
}

3. Generate Secure Session IDs

Use Node’s built-in crypto.randomUUID() for cryptographically secure session IDs—way more reliable than rolling your own random string:

function generateSessionId() {
  return crypto.randomUUID();
}

4. Set Cookies Correctly (Fix Consistency)

When setting the session cookie, include critical parameters to ensure it works across all routes and stays secure:

function setSessionCookie(res, sessionId) {
  res.setHeader('Set-Cookie', [
    `sessionId=${sessionId}; Path=/; HttpOnly; Max-Age=86400; SameSite=Lax`
  ]);
  // Key params explained:
  // - Path=/: Makes the cookie accessible across all routes (solves your inconsistency issue!)
  // - HttpOnly: Blocks frontend JS from accessing the cookie (prevents XSS attacks)
  // - Max-Age=86400: Cookie expires after 1 day (in seconds)
  // - SameSite=Lax: Reduces CSRF attack risk
}

5. Parse Cookies from Requests

A helper function to extract cookies from the request header:

function parseCookies(req) {
  const cookieHeader = req.headers.cookie || '';
  return cookieHeader.split(';').reduce((cookies, cookie) => {
    const [name, value] = cookie.trim().split('=');
    if (name && value) cookies[name] = value;
    return cookies;
  }, {});
}

6. Authenticate Users via Sessions

Check if a request has a valid session by looking up the session ID from the cookie:

function getAuthenticatedUser(req) {
  const cookies = parseCookies(req);
  const sessionId = cookies.sessionId;

  if (!sessionId) return null;
  const userId = sessions.get(sessionId);
  if (!userId) return null;

  // Fetch full user data from our mock database
  return Array.from(users.values()).find(user => user.id === userId);
}

7. Handle Logout

Delete the session from storage and invalidate the cookie:

function destroySession(res, sessionId) {
  sessions.delete(sessionId);
  // Set cookie expiry to 0 to delete it
  res.setHeader('Set-Cookie', [
    `sessionId=; Path=/; HttpOnly; Max-Age=0`
  ]);
}

8. Wire It All Into the Server

Finally, add routes for login, logout, and a protected dashboard:

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json');

  // Login Route (POST /login)
  if (req.method === 'POST' && req.url === '/login') {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      try {
        const { email, password } = JSON.parse(body);
        const user = validateUser(email, password);

        if (!user) {
          res.writeHead(401);
          return res.end(JSON.stringify({ message: 'Invalid email or password' }));
        }

        // Create new session
        const sessionId = generateSessionId();
        sessions.set(sessionId, user.id);
        setSessionCookie(res, sessionId);

        res.writeHead(200);
        res.end(JSON.stringify({ message: 'Login successful', user: { id: user.id, email } }));
      } catch (err) {
        res.writeHead(400);
        res.end(JSON.stringify({ message: 'Invalid request body' }));
      }
    });
    return;
  }

  // Protected Dashboard Route (GET /dashboard)
  if (req.method === 'GET' && req.url === '/dashboard') {
    const user = getAuthenticatedUser(req);
    if (!user) {
      res.writeHead(403);
      return res.end(JSON.stringify({ message: 'Unauthorized: Please log in first' }));
    }

    res.writeHead(200);
    res.end(JSON.stringify({ message: `Welcome to your dashboard, user #${user.id}!` }));
  }

  // Logout Route (POST /logout)
  if (req.method === 'POST' && req.url === '/logout') {
    const cookies = parseCookies(req);
    destroySession(res, cookies.sessionId);

    res.writeHead(200);
    res.end(JSON.stringify({ message: 'Logout successful' }));
  }

  // 404 Route
  res.writeHead(404);
  res.end(JSON.stringify({ message: 'Route not found' }));
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

Production-Ready Tips

  • Persistent Session Storage: The in-memory sessions map will lose data when the server restarts. Use a database like SQLite (with the native sqlite3 driver) to store sessions long-term.
  • Password Security: Replace the simple SHA256 hash with crypto.pbkdf2 or crypto.scrypt which use salting to prevent rainbow table attacks.
  • HTTPS: Always use HTTPS in production, and add the Secure flag to your cookies to ensure they’re only sent over encrypted connections.
  • Session Cleanup: Add a cron job to periodically delete expired sessions from your database to save space.

内容的提问来源于stack exchange,提问作者Ionut Eugen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:38:38