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

短信认证开发疑问:如何在控制器不同方法间共享验证码数据

Hey there! Let's break down your problem first—since /sendsms and /confirm_sms are two totally separate HTTP requests, next() won't help here (that's only for passing control along the middleware chain of a single request). You need a way to store the generated auth code between these two requests, and here are some practical, production-ready ways to do it:

The core idea is to link the auth code with the user's phone number and store this pair temporarily. For development, you can use an in-memory Map (but note this resets when your server restarts—never use this in production). For production, Redis is ideal because it supports automatic key expiration, which is perfect for time-sensitive auth codes.

Development Example (In-Memory Storage)

// Add this at the top of your controller file
const authCodeStore = new Map(); // Key: phone number, Value: auth code

module.exports.send_post = (req, res, next) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = create_auth_num();

  // Store the code with a 5-minute expiration (adjust as needed)
  authCodeStore.set(client_phone_number, client_auth_number);
  setTimeout(() => {
    authCodeStore.delete(client_phone_number);
  }, 5 * 60 * 1000);

  send_message(client_phone_number, client_auth_number);
  // ✅ Don't return the auth code to the frontend! That's a huge security risk.
  res.json({ message: "Verification code sent" });
};

module.exports.confirm_sms_post = (req, res) => {
  const client_phone_number = req.body.phoneNum; // Make sure frontend sends the phone number here too
  const client_auth_number = req.body.auth;
  const server_auth_number = authCodeStore.get(client_phone_number);

  if (server_auth_number && client_auth_number === server_auth_number) {
    authCodeStore.delete(client_phone_number); // Delete after successful verification to prevent reuse
    res.json("OK.");
  } else {
    res.json("False.");
  }
};

Production Example (Redis)

First, install Redis and the client package (npm install redis), then:

const redis = require('redis');
const redisClient = redis.createClient({ /* your Redis config */ });

module.exports.send_post = async (req, res, next) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = create_auth_num();

  // Store in Redis with a 5-minute expiration (300 seconds)
  await redisClient.setEx(client_phone_number, 300, client_auth_number);

  send_message(client_phone_number, client_auth_number);
  res.json({ message: "Verification code sent" });
};

module.exports.confirm_sms_post = async (req, res) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = req.body.auth;
  const server_auth_number = await redisClient.get(client_phone_number);

  if (server_auth_number && client_auth_number === server_auth_number) {
    await redisClient.del(client_phone_number);
    res.json("OK.");
  } else {
    res.json("False.");
  }
};
2. Use User Sessions (If You Already Have Session Support)

If your app uses sessions (like express-session), you can store the auth code directly in the user's session. This works well if users are already logged in, or if you use anonymous sessions.

module.exports.send_post = (req, res, next) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = create_auth_num();

  // Store auth details in the session
  req.session.smsAuth = {
    phone: client_phone_number,
    code: client_auth_number,
    expires: Date.now() + 5 * 60 * 1000
  };

  send_message(client_phone_number, client_auth_number);
  res.json({ message: "Verification code sent" });
};

module.exports.confirm_sms_post = (req, res) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = req.body.auth;
  const sessionAuth = req.session.smsAuth;

  // Check if session data exists, is valid, and hasn't expired
  if (!sessionAuth || sessionAuth.phone !== client_phone_number || Date.now() > sessionAuth.expires) {
    return res.json("False.");
  }

  if (client_auth_number === sessionAuth.code) {
    delete req.session.smsAuth; // Clean up after success
    res.json("OK.");
  } else {
    res.json("False.");
  }
};
3. Encrypted Token (Less Secure, Use Only If Necessary)

You can encrypt the auth code + phone number into a token, return it to the frontend, and have the frontend send it back with the verification request. This avoids server-side storage but has security risks (if the token is intercepted, attackers can reuse it).

const crypto = require('crypto');
const SECRET_KEY = 'your-strong-secret-key'; // Use a secure, environment-stored key in production

module.exports.send_post = (req, res, next) => {
  const client_phone_number = req.body.phoneNum;
  const client_auth_number = create_auth_num();

  // Create encrypted token with expiration
  const authData = JSON.stringify({
    phone: client_phone_number,
    code: client_auth_number,
    expires: Date.now() + 5 * 60 * 1000
  });
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), iv);
  let encrypted = cipher.update(authData);
  encrypted = Buffer.concat([encrypted, cipher.final()]);

  res.json({
    message: "Verification code sent",
    token: `${iv.toString('hex')}:${encrypted.toString('hex')}`
  });
};

module.exports.confirm_sms_post = (req, res) => {
  const client_auth_number = req.body.auth;
  const token = req.body.token;

  if (!token) return res.json("False.");

  // Decrypt the token
  const [ivHex, encryptedHex] = token.split(':');
  const iv = Buffer.from(ivHex, 'hex');
  const encryptedText = Buffer.from(encryptedHex, 'hex');
  const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), iv);
  let decrypted = decipher.update(encryptedText);
  decrypted = Buffer.concat([decrypted, decipher.final()]);

  try {
    const authData = JSON.parse(decrypted.toString());
    if (Date.now() > authData.expires) return res.json("False.");
    if (authData.code === client_auth_number) {
      res.json("OK.");
    } else {
      res.json("False.");
    }
  } catch (err) {
    res.json("False.");
  }
};

Critical Notes:

  • Never return the auth code directly to the frontend (your original send_post does this—fix that immediately, as it bypasses the entire SMS verification purpose).
  • Always set an expiration time for auth codes to prevent them from being used indefinitely.
  • Delete the auth code from storage immediately after successful verification to stop reuse.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:59:03