移动端API认证:不推荐用idToken,求accessToken服务端验证方案
基于Firebase生态的理想认证实现方案
1. 理清Token类型的对应关系
Auth0提到的「ID Token用于身份验证、Access Token用于API访问」原则,在Firebase体系中可这样对齐:
- Firebase的ID Token本身兼具身份验证与API授权能力,官方默认推荐用它做移动端到Cloud Functions的认证;如果要严格区分身份凭证与API访问凭证,可通过自定义JWT实现专属的Access Token。
2. 移动端Token获取与API调用
- 移动端通过Firebase Auth完成登录后,调用
getIdToken()方法获取ID Token(默认1小时过期,需定期刷新),请求Cloud Functions时将Token放在Authorization头中,格式为Bearer <idToken>。 - 若需专门的Access Token,可先调用专用Cloud Functions接口,传入refreshToken换取自定义生成的Access Token,再用该Token调用其他API。
3. Cloud Functions端的Token验证(官方推荐方案)
使用Firebase Admin SDK验证ID Token是最直接的方式,步骤如下:
- 安装依赖:
npm install firebase-admin --save - 编写验证中间件并在API中使用:
const admin = require('firebase-admin'); admin.initializeApp(); async function verifyIdToken(req, res, next) { const idToken = req.headers.authorization?.split('Bearer ')[1]; if (!idToken) return res.status(401).send('Unauthorized'); try { const decodedToken = await admin.auth().verifyIdToken(idToken); req.user = decodedToken; next(); } catch (err) { return res.status(403).send('Invalid token'); } } // 示例API函数 exports.userDataApi = functions.https.onRequest((req, res) => { verifyIdToken(req, res, () => { // 此处处理业务逻辑,req.user包含用户uid、邮箱等身份信息 res.status(200).send({ uid: req.user.uid }); }); });
4. 自定义Access Token的实现方案(严格遵循ID Token不碰API的原则)
若要完全分离身份凭证与API访问凭证,可通过自定义JWT实现Access Token:
步骤1:移动端换取Access Token
编写Cloud Functions接口,接收refreshToken并生成自定义Access Token:
const jwt = require('jsonwebtoken'); const serviceAccount = require('./path/to/service-account-key.json'); exports.getAccessToken = functions.https.onRequest(async (req, res) => { const refreshToken = req.body.refreshToken; if (!refreshToken) return res.status(400).send('Refresh token required'); try { const userRecord = await admin.auth().verifyRefreshToken(refreshToken); // 生成有效期15分钟的自定义JWT const accessToken = jwt.sign( { uid: userRecord.uid, scope: 'api:read api:write' // 自定义权限声明 }, serviceAccount.private_key, { algorithm: 'RS256', issuer: serviceAccount.client_email, expiresIn: '15m' } ); res.status(200).send({ accessToken }); } catch (err) { res.status(403).send('Invalid refresh token'); } });
步骤2:API端验证自定义Access Token
编写验证中间件验证JWT签名与有效性:
async function verifyAccessToken(req, res, next) { const accessToken = req.headers.authorization?.split('Bearer ')[1]; if (!accessToken) return res.status(401).send('Unauthorized'); try { const decoded = jwt.verify( accessToken, serviceAccount.public_key, { issuer: serviceAccount.client_email, algorithms: ['RS256'] } ); req.user = decoded; next(); } catch (err) { return res.status(403).send('Invalid access token'); } } // 在API函数中使用该中间件 exports.protectedApi = functions.https.onRequest((req, res) => { verifyAccessToken(req, res, () => { // 处理权限校验与业务逻辑 res.status(200).send('Access granted'); }); });
5. 最佳实践总结
- 在Firebase生态中,使用ID Token认证Cloud Functions是官方推荐的安全方案,无需额外自定义,已满足短过期、可验证、防篡改等要求。
- 若坚持严格分离身份凭证与API访问凭证,自定义JWT Access Token是可行方案,但需自行管理签名密钥、过期时间与权限声明。
- 所有Token传输必须通过HTTPS,避免明文泄露;移动端需定期刷新Token,确保凭证有效性。
内容的提问来源于stack exchange,提问作者Rapha
相关产品推荐
相关产品推荐

