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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:52:59