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

Flutter调用Firebase Cloud Functions遇认证挑战格式错误求助

Firebase Cloud Functions调用报错:ClientException: 服务器发送的身份验证质询格式不正确

我需要在Firebase中实现特定用户锁定交易的功能,核心要求是客户端锁定的价格必须与服务器实时价格一致,防止恶意篡改。但调用Cloud Functions时触发如下错误:
ClientException: The authentication challenge sent by the server is not correctly formatted


Flutter客户端代码

// dealId示例值: "md4b6c3uoe75zt2zmj893",clientPrice示例值: 82.15
Future<bool> lockDeal(String dealId, double clientPrice) async {
  print('======= DIAGNOSE: HTTP LOCKDEAL FUNCTIE GESTART =======');
  print('DealID: $dealId, ClientPrice: $clientPrice');
  
  if (_auth == null || _auth!.currentUser == null) {
    print('DIAGNOSE FOUT: Geen gebruiker ingelogd');
    return false;
  }
  
  try {
    // 1. 获取最新ID令牌
    final idToken = await _auth!.currentUser!.getIdToken(true);
    
    // 空值检查:确认令牌已获取
    if (idToken == null) {
      print('DIAGNOSE FOUT: Token kon niet worden opgehaald');
      return false;
    }
    
    // 安全截取令牌前20位打印
    print('Token verkregen (eerste 20 tekens): ${idToken.substring(0, min(idToken.length, 20))}...');
    
    // 2. 检查交易是否可用
    final isAvailable = await isDealAvailable(dealId);
    if (!isAvailable) {
      print('DIAGNOSE FOUT: Deal is niet beschikbaar: $dealId');
      return false;
    }
    
    // 3. 构建请求URL和请求头
    final url = 'https://europe-west1-{My-Project-Name}.cloudfunctions.net/lockDeal';
    
    final headers = {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer $idToken'
    };
    
    final body = jsonEncode({
      'dealId': dealId
    });
    
    print('HTTP aanvraag: URL=$url');
    print('HTTP aanvraag: Headers=${headers.toString().replaceAll(idToken, "[TOKEN VERBORGEN]")}');
    print('HTTP aanvraag: Body=$body');
    
    // 4. 发送HTTP请求
    final response = await http.post(
      Uri.parse(url),
      headers: headers,
      body: body
    );
    
    print('HTTP respons status: ${response.statusCode}');
    print('HTTP respons body: ${response.body}');
    
    // 5. 处理响应
    if (response.statusCode == 200) {
      final responseData = jsonDecode(response.body);
      
      if (responseData['success'] == true) {
        final serverPrice = responseData['price'] is num ? 
            (responseData['price'] as num).toDouble() : clientPrice;
        
        print('Deal vergrendeld! Server prijs: $serverPrice');
        return true;
      } else {
        print('Functie gaf success=false: ${responseData['message'] ?? 'Geen foutmelding'}');
        return false;
      }
    } else {
      print('HTTP fout: ${response.statusCode}');
      print('Fout details: ${response.body}');
      return false;
    }
  } catch (e) {
    print('Algemene fout bij vergrendelen deal: $e');
    return false;
  }
}

Firebase Cloud Functions代码(index.js)

exports.lockDeal = functions.region('europe-west1').https.onRequest(async (req, res) => {
  // 严格CORS策略
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

  // 直接处理预请求
  if (req.method === 'OPTIONS') {
    return res.status(204).send('');
  }

  // 仅允许POST方法
  if (req.method !== 'POST') {
    return res.status(405).json({ success: false, message: 'Method not allowed' });
  }

  try {
    // 严格身份验证检查
    const authHeader = req.headers.authorization;
    if (!authHeader?.startsWith('Bearer ')) {
      console.error('Missing auth header');
      return res.status(401).json({ success: false, message: 'Unauthorized' });
    }

    const idToken = authHeader.split('Bearer ')[1];
    const decodedToken = await admin.auth().verifyIdToken(idToken);
    const userId = decodedToken.uid;

    // 请求体验证
    if (!req.body?.dealId) {
      return res.status(400).json({ success: false, message: 'Bad request' });
    }

    const dealId = req.body.dealId;
    const dealRef = admin.database().ref(`deals/${dealId}`);
    
    // 事务更新
    const result = await dealRef.transaction((deal) => {
      if (!deal) return;
      if (deal.status === 'locked') return deal;
      
      deal.status = 'locked';
      deal.lockedByUserId = userId;
      deal.lockedPrice = calculateCurrentPrice(deal);
      deal.lockedAt = Date.now();
      return deal;
    });

    if (!result.committed) {
      return res.status(409).json({ 
        success: false, 
        message: result.snapshot.val()?.status === 'locked' 
          ? 'Deal already locked' 
          : 'Conflict'
      });
    }

    // 更新Firestore
    await admin.firestore().collection('locked_deals').doc(dealId).set({
      ...result.snapshot.val(),
      lockedAt: admin.firestore.FieldValue.serverTimestamp(),
    });

    return res.json({ 
      success: true, 
      dealId: dealId,
      price: result.snapshot.val().lockedPrice
    });

  } catch (error) {
    console.error('Critical error:', error);
    return res.status(500).json({ 
      success: false, 
      message: 'Internal server error' 
    });
  }
})

完整错误输出

I/flutter (16861): ======= DIAGNOSE: HTTP LOCKDEAL FUNCTION StARTED =======
I/flutter (16861): DealID: md4b6c3uoe75zt2zmj893, ClientPrice: 82.15
W/System  (16861): Ignoring header X-Firebase-Locale because its value was null.
D/TrafficStats(16861): tagSocket(123) with statsTag=0xffffffff, statsUid=-1
D/FirebaseAuth(16861): Notifying id token listeners about user ( {some id} ).
I/flutter (16861): Token received: {some api code}...
I/flutter (16861): HTTP aanvraag: URL=https://europe-west1-{My-Project-Here}.cloudfunctions.net/lockDeal
I/flutter (16861): HTTP request: Headers={Content-Type: application/json, Accept: application/json, Authorization: Bearer [TOKEN VERBORGEN]}
I/flutter (16861): HTTP request: Body={"dealId":"md4b6c3uoe75zt2zmj893"}
I/flutter (16861): General error when locking deal: ClientException: The authentication challenge sent by the server is not correctly formatted.

排查与解决方向

  • 验证Cloud Functions URL:确认URL中的项目名称、区域与部署信息完全匹配,函数已成功上线。
  • 检查SSL证书:若使用测试环境的自签名证书,Flutter的http库会拒绝连接,需改用正式HTTPS链接或配置证书信任。
  • 规范请求头格式:确保Authorization头严格遵循Bearer {token}格式,无多余空格、换行或特殊字符。
  • CORS逻辑校验:确认OPTIONS预请求处理正确,响应头包含完整的跨域允许配置,避免跨域引发的验证异常。
  • Firebase Admin初始化检查:确保Cloud Functions中已正确初始化Firebase Admin SDK,未初始化会导致令牌验证失败,间接触发格式错误。

内容的提问来源于stack exchange,提问作者Kaja Koenders

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:17:04