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

Firebase Auth手机号ID认证及Flutter+RevenueCat订阅防刷免费额度方案

1. 如何通过手机号ID(Phone-ID)实现Firebase Auth用户认证?

这里的Phone-ID通常指设备的唯一标识(如Android的Android ID、iOS的IDFV),Firebase Auth无原生支持该方式的认证,需通过自定义Token实现,步骤如下:

  • 步骤1:获取设备唯一Phone-ID
    使用Flutter的device_info_plus包获取设备标识:

    import 'package:device_info_plus/device_info_plus.dart';
    import 'dart:io';
    
    Future<String?> getDeviceId() async {
      final deviceInfo = DeviceInfoPlugin();
      if (Platform.isAndroid) {
        final androidInfo = await deviceInfo.androidInfo;
        return androidInfo.id; // Android ID
      } else if (Platform.isIOS) {
        final iosInfo = await deviceInfo.iosInfo;
        return iosInfo.identifierForVendor; // IDFV
      }
      return null;
    }
    

    注意:Android 10+无法获取IMEI(需特殊权限),推荐用Android ID;iOS的IDFV在重置设备后会变更,但适合作为普通设备标识。

  • 步骤2:后端生成Firebase自定义Token
    用Firebase Admin SDK(比如Cloud Functions)生成绑定该Phone-ID的自定义Token,将Phone-ID作为用户UID:

    const admin = require('firebase-admin');
    exports.createCustomToken = functions.https.onCall(async (data, context) => {
      const deviceId = data.deviceId;
      if (!deviceId) throw new functions.https.HttpsError('invalid-argument', 'Device ID missing');
      
      // 可在此处添加设备ID合法性校验逻辑
      const token = await admin.auth().createCustomToken(deviceId);
      return { token };
    });
    
  • 步骤3:Flutter端用自定义Token登录
    获取设备ID后调用云函数拿到Token,再完成Firebase Auth登录:

    final deviceId = await getDeviceId();
    final HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('createCustomToken');
    final result = await callable.call({'deviceId': deviceId});
    final token = result.data['token'];
    
    await FirebaseAuth.instance.signInWithCustomToken(token);
    
2. 解决更换Firebase账号重复领取免费额度的问题

核心思路是将免费额度的领取状态与非Firebase账号的唯一标识绑定,以下是可行方案:

方案一:绑定设备唯一标识(最简方案)

  • 用Firestore或实时数据库存储已领取免费额度的设备ID列表
  • 用户申请免费额度时,先查询数据库:
    final deviceId = await getDeviceId();
    final doc = FirebaseFirestore.instance.collection('free_tier_claims').doc(deviceId);
    final snapshot = await doc.get();
    
    if (!snapshot.exists) {
      // 发放免费额度
      await doc.set({'claimedAt': FieldValue.serverTimestamp()});
      // 执行额度发放逻辑(比如更新用户本地或云端的额度数据)
    } else {
      // 提示用户已领取过免费额度
    }
    
  • 优势:实现简单;劣势:设备重置后用户可再次领取,适合风险较低的场景

方案二:绑定RevenueCat用户ID(推荐结合订阅场景)

  • 将设备ID作为RevenueCat的用户ID,而非Firebase Auth的UID,确保订阅/免费额度状态与设备绑定:
    final deviceId = await getDeviceId();
    await Purchases.configure(
      PurchasesConfiguration('your_revenuecat_api_key')
        ..appUserID = deviceId,
    );
    
    // 检查该RevenueCat用户是否已领取免费额度
    final purchaserInfo = await Purchases.getPurchaserInfo();
    if (!purchaserInfo.entitlements.all.containsKey('free_tier')) {
      // 发放免费额度(可通过RevenueCat的Promotional Offers或自定义字段记录)
      await Purchases.logIn(deviceId); // 确保用户身份固定
    }
    
  • 优势:直接与订阅系统联动,状态统一;劣势:同样受设备重置影响,但可配合后端校验加强

方案三:后端统一校验(最高安全性)

  • 搭建独立后端服务,维护设备ID/手机号(若已收集)与免费额度的绑定关系
  • 发放免费额度前必须调用后端接口校验,接口需验证请求合法性(如通过Firebase App Check):
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
    // Flutter端调用后端接口
    final response = await http.post(
      Uri.parse('https://your-backend.com/check-free-tier'),
      body: {'deviceId': deviceId, 'firebaseUid': FirebaseAuth.instance.currentUser?.uid},
      headers: {'Authorization': 'Bearer ${await FirebaseAuth.instance.currentUser?.getIdToken()}'},
    );
    
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      if (data['canClaim']) {
        // 发放免费额度
      } else {
        // 提示已领取
      }
    }
    
  • 优势:可灵活添加风控规则(如IP限制、手机号绑定);劣势:需要额外维护后端

补充安全措施

  • 启用Firebase App Check,防止恶意伪造设备ID请求
  • 对设备ID进行哈希处理后存储,避免明文泄露

内容的提问来源于stack exchange,提问作者matti peterbull

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:50:38