如何在Vercel Edge Functions中为Firebase Auth用户设置custom user claims?
解决Vercel Edge Functions中设置Firebase Auth自定义用户Claims的方案
由于Vercel Edge Functions不支持Firebase Admin SDK,可通过以下两种方案实现需求:
方案一:直接调用Firebase Auth REST API
利用Firebase Auth的REST接口完成操作,无需依赖Admin SDK,适配Edge环境。
1. 验证ID Token(安全必选)
先确保用户提供的ID Token合法且与uid匹配,可使用jose库手动验证JWT:
import { jwtVerify } from 'jose'; async function verifyIdToken(idToken, projectId) { // 获取Firebase公钥 const publicKeys = await fetch('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com') .then(res => res.json()); const key = new TextEncoder().encode(publicKeys[Object.keys(publicKeys)[0]]); const decoded = await jwtVerify(idToken, key, { issuer: `https://securetoken.google.com/${projectId}`, audience: projectId, }); // 验证uid一致性 if (decoded.payload.uid !== uid) { throw new Error('UID与Token不匹配'); } return decoded.payload; }
2. 生成服务端访问令牌
调用Auth REST API需要OAuth2授权,用服务账号生成访问令牌:
import { SignJWT } from 'jose'; async function getServiceAccountAccessToken(clientEmail, privateKey) { const jwt = await new SignJWT({ scope: 'https://www.googleapis.com/auth/firebase.auth' }) .setIssuedAt() .setExpirationTime('1h') .setIssuer(clientEmail) .setAudience('https://oauth2.googleapis.com/token') .sign(new TextEncoder().encode(privateKey)); const tokenRes = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: jwt, }), }); const tokenData = await tokenRes.json(); return tokenData.access_token; }
3. 设置自定义Claims
调用Auth的accounts:update接口完成设置:
async function setCustomClaims(uid, claims, apiKey, accessToken) { const res = await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:update?key=${apiKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}`, }, body: JSON.stringify({ localId: uid, customAttributes: JSON.stringify(claims), }), }); if (!res.ok) { const error = await res.json(); throw new Error(error.error.message); } return await res.json(); }
方案二:通过Firebase Cloud Functions中转
将设置Claims的逻辑放在支持Admin SDK的Cloud Functions中,Edge函数仅负责调用中转接口,实现更简单。
1. 部署Cloud Function
编写并部署支持Admin SDK的云函数:
// Cloud Functions代码 const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.setCustomClaims = functions.https.onCall(async (data, context) => { // 可选:验证调用者身份(如检查context.auth) const { uid, claims } = data; await admin.auth().setCustomUserClaims(uid, claims); return { success: true }; });
执行部署命令:firebase deploy --only functions
2. Edge函数调用中转接口
在Vercel Edge Functions中调用上述云函数:
// Vercel Edge Function代码 export async function POST(request) { const { uid, idToken, claims } = await request.json(); // 可选:先验证ID Token(参考方案一的验证逻辑) const res = await fetch('https://[REGION]-[PROJECT_ID].cloudfunctions.net/setCustomClaims', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${idToken}`, // 传给Cloud Function验证身份 }, body: JSON.stringify({ uid, claims }), }); const data = await res.json(); return new Response(JSON.stringify(data), { status: res.status }); }
注意事项
- 服务账号私钥、项目ID等敏感信息需存储在Vercel环境变量中,禁止硬编码。
- Edge环境不支持文件系统,所有配置需通过环境变量传递。
- 无论哪种方案,都必须验证ID Token的合法性,防止非法请求篡改用户Claims。
内容的提问来源于stack exchange,提问作者GorvGoyl
相关产品推荐
相关产品推荐

