如何生成30分钟后自动过期的URL?基于NodeJS实现Google Cloud相关业务需求
NodeJS 环境下30分钟过期用户访问URL实现方案
整体流程说明
- 生成URL阶段:用用户UUID + 过期时间戳生成签名,拼接成可访问的Cloud Function触发地址,签名逻辑保证URL无法被恶意篡改
- 验证阶段:Cloud Function接收到请求后,先校验签名有效性和时间是否过期,过期直接返回403,有效则从Firestore拉取用户信息返回
1. 依赖安装
本地开发需要提前安装以下依赖:
npm install @google-cloud/functions-framework @google-cloud/firestore crypto
注:部署到Cloud Function时,@google-cloud/functions-framework和@google-cloud/firestore会由平台默认提供,也可以手动写入package.json统一管理
2. 生成带过期时间的签名URL代码(服务端生成URL时调用)
用Node内置crypto模块生成HMAC签名,无需额外第三方依赖:
const crypto = require('crypto'); // 签名密钥建议存在GCP Secret Manager中,不要硬编码到代码里 const SIGN_SECRET = process.env.SIGN_SECRET || 'your-custom-secret-key'; function generateExpiringUrl(userUuid, expireMinutes = 30) { const expireAt = Date.now() + expireMinutes * 60 * 1000; // 构造签名原始串 const signRaw = `${userUuid}:${expireAt}`; // 生成HMAC SHA256签名 const signature = crypto.createHmac('sha256', SIGN_SECRET).update(signRaw).digest('hex'); // 拼接为Cloud Function访问地址,替换为你自己的Cloud Function触发域名即可 return `https://<your-region>-<your-gcp-project-id>.cloudfunctions.net/getUserInfo?uuid=${userUuid}&expire=${expireAt}&sign=${signature}`; }
3. Cloud Function 业务逻辑代码
部署到GCP Cloud Function的核心代码,负责请求校验、Firestore查询和结果返回:
const functions = require('@google-cloud/functions-framework'); const { Firestore } = require('@google-cloud/firestore'); const crypto = require('crypto'); const SIGN_SECRET = process.env.SIGN_SECRET || 'your-custom-secret-key'; const firestore = new Firestore(); functions.http('getUserInfo', async (req, res) => { // 按需配置CORS头,生产环境不建议用*通配符 res.set('Access-Control-Allow-Origin', '*'); const { uuid, expire, sign } = req.query; // 校验参数完整性 if (!uuid || !expire || !sign) { return res.status(400).send('Invalid request parameters'); } // 校验URL是否过期 const now = Date.now(); if (now > parseInt(expire)) { return res.status(403).send('URL has expired'); } // 校验签名是否合法,避免URL被篡改 const signRaw = `${uuid}:${expire}`; const validSign = crypto.createHmac('sha256', SIGN_SECRET).update(signRaw).digest('hex'); if (validSign !== sign) { return res.status(403).send('Invalid URL signature'); } // 从Firestore查询用户信息,示例中用户集合名为users,文档ID为用户UUID try { const userDoc = await firestore.collection('users').doc(uuid).get(); if (!userDoc.exists) { return res.status(404).send('User not found'); } const userInfo = userDoc.data(); // 按需返回HTML页面或JSON数据,返回JSON直接调用res.json(userInfo)即可 res.send(` <!DOCTYPE html> <html> <head><title>Personal Information</title></head> <body> <h1>Your Personal Information</h1> <p>Name: ${userInfo.name || '-'}</p> <p>Email: ${userInfo.email || '-'}</p> <!-- 补充其他需要展示的用户字段 --> </body> </html> `); } catch (err) { console.error('Firestore query error:', err); return res.status(500).send('Server internal error'); } });
4. 部署注意事项
- 给Cloud Function绑定的服务账号授予
datastore.user角色,保证有Firestore访问权限 - 签名密钥不要硬编码,建议存入GCP Secret Manager后通过Cloud Function环境变量引入
- 生产环境需要收紧CORS规则,仅允许业务域名访问
内容的提问来源于stack exchange,提问作者Shubham Kandpal
相关产品推荐
相关产品推荐

