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

Flutter调用Firebase可调用云函数遇权限拒绝问题求助

Flutter调用Firebase可调用云函数遭遇权限拒绝问题

错误日志

W/FirebaseContextProvider( 3655): Error getting App Check token. Error: com.google.firebase.FirebaseException: Error returned from API. code: 403 body: App attestation failed.
D/TrafficStats( 3655): tagSocket(294) with statsTag=0xffffffff, statsUid=-1
E/flutter ( 3655): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: [firebase_functions/permission-denied] PERMISSION_DENIED
E/flutter ( 3655):
E/flutter ( 3655): #0      StandardMethodCodec.decodeEnvelope
message_codecs.dart:653
E/flutter ( 3655): #1      MethodChannel._invokeMethod
platform_channel.dart:315
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #2      MethodChannelHttpsCallable.call
method_channel_https_callable.dart:22
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #3      HttpsCallable.call
https_callable.dart:49
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #4      _SendFeedbackModalBottomSheetState.build.<anonymous closure>
send_feedback.dart:90
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655):
E/flutter ( 3655): #0      StandardMethodCodec.decodeEnvelope
message_codecs.dart:653
E/flutter ( 3655): #1      MethodChannel._invokeMethod
platform_channel.dart:315
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #2      MethodChannelHttpsCallable.call
method_channel_https_callable.dart:22
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #3      HttpsCallable.call
https_callable.dart:49
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655): #4      _SendFeedbackModalBottomSheetState.build.<anonymous closure>
send_feedback.dart:90
E/flutter ( 3655): <asynchronous suspension>
E/flutter ( 3655):

Flutter调用代码

final HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('sendFeedback');
final resp = await callable.call<String, dynamic>{
  'email': 'customer@example.com',
  'message': message,
};

云函数代码

const sendgridApiKey = functions.config().sendgrid.key;
sgMail.setApiKey(sendgridApiKey);
export const sendFeedback = functions.https.onCall(async (data, context) => {
  // Check if the user is authenticated
  if (!context.auth) {
    throw new functions.https.HttpsError("unauthenticated", "User is not authenticated");
  }

  const message = data.message;

  try {
    // Compose the email message
    const emailMessage = {
      to: "hello@example.com",
      from: "no-reply@example.com",
      subject: "Feedback from user",
      text: message,
    };

    // Send the email using SendGrid
    await sgMail.send(emailMessage);

    return {
      success: true, message: "Email sent successfully",
    };
  } catch (error) {
    console.error("Error sending email:", error);
    throw new functions.https.HttpsError("internal", "An error occurred while sending the email");
  }
});

问题背景

  • 该问题在模拟器和真机上均会出现
  • 已确认「App Engine默认服务账号」角色为「Editor」
  • 更新:已使用App Check调试token解决了App attestation失败问题,但权限拒绝问题仍然存在

解决方案建议

1. 确保调用前用户已完成Firebase认证

云函数代码中明确校验了context.auth,只有认证用户才能调用。Flutter端调用函数前必须确保用户已通过Firebase Auth完成登录:

  • 调用函数前先检查FirebaseAuth.instance.currentUser是否不为null,若未登录则引导用户完成登录流程(如邮箱密码登录、匿名登录等)

2. 配置云函数的IAM调用权限

检查云函数的IAM权限设置,确保调用者拥有函数的执行权限:

  • 打开Firebase控制台,进入「函数」页面,找到sendFeedback函数
  • 点击「权限」标签,添加对应成员(测试阶段可临时添加allUsers,生产环境需严格限制)
  • 为该成员授予「Cloud Functions Invoker」角色

3. 验证App Check的云函数侧配置

虽然已解决Token获取问题,仍需确认云函数是否启用了App Check验证:

  • 若云函数启用了App Check验证,需确保Firebase控制台的App Check设置中已添加调试token(针对测试环境)
  • 生产环境需确保App Check的提供者(如Play Integrity、App Attest)配置正确

4. 重新部署云函数并检查状态

确认云函数已正确部署,无部署错误:

  • 使用命令firebase deploy --only functions重新部署函数
  • 查看部署日志,确保没有配置错误或依赖缺失

5. 确认Firebase Auth初始化完成

Flutter端需确保Firebase Auth已完成初始化,避免在Auth未就绪时调用函数:

  • 可通过监听FirebaseAuth.instance.authStateChanges()确认用户状态稳定后,再执行函数调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:30:38