swift - 创建 FCM 设备组返回 401

标签 swift firebase firebase-cloud-messaging

我正在尝试为我的一个用户创建一个 FCM 设备组,但是在发布 create 请求时,我得到了 401 响应代码:

这是我的POST请求:

if let url = URL(string: "https://android.googleapis.com/gcm/notification") {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        request.addValue(apiKey, forHTTPHeaderField: "Authorization")
        request.addValue(senderId, forHTTPHeaderField: "project_id")

        let registration_ids = [deviceToken] as! [String]
        let jsonToSend = ["operation": "create",
                          "notification_key_name": LocalUser.shared.firebaseId,
                          "registration_ids": registration_ids
            ] as [String : Any]

        do {
            let jsonData = try JSONSerialization.data(withJSONObject: jsonToSend, options: JSONSerialization.WritingOptions.prettyPrinted)
            request.httpBody = jsonData

            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
                    print("statusCode should be 200, but is \(httpStatus.statusCode)")
                    print("response = \(response.debugDescription)")
                } else if let httpStatus = response as? HTTPURLResponse {

                    print("statusCode is \(httpStatus.statusCode)")
                    print("response = \(response.debugDescription)")

                }
            }
            task.resume()
        } catch {
            print("could not serialize json")
        }
    }

您还知道如果我尝试使用已经存在的 notification_key_name 创建一个 device group 会发生什么。新的 device key 是否会添加到现有组中?或者有没有办法检查一个组是否存在?

最佳答案

在这个声明中:

request.addValue(apiKey, forHTTPHeaderField: "Authorization")

apiKey 必须是项目设置中的服务器 key ,以 key= 为前缀。 例如:key=AAAPWK_CVGw:APA91b...saklHTO29fTk

您在评论中指出您是从客户端设备执行此操作的。将您的服务器 key 放在设备代码中是不安全的。

更安全的替代方法是在 Cloud Function 中执行设备组创建。下面是通过将组创建参数存储在数据库中触发的基本实现。仅示例;没有经过彻底测试;欢迎更正/评论。

const rqstProm = require('request-promise');

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.createDeviceGroup = functions.database.ref("/deviceGroup/create/params")
       .onWrite(event => {
    const serverKey = 'AAAAXp6june:APA91bF-Nq9pm...3dD5pZxVsNBfX0O3_Xf-jV472nfn-sb';
    const senderId = '271828182845';
    // TODO add checks for valid request params
    const request = event.data.val();
    const groupName = request.groupName;
    const tokens = Object.keys(request.tokens);

    console.log('groupName=', groupName, 'tokens=', tokens.length);

    const options = {
        method: 'POST',
        uri: 'https://android.googleapis.com/gcm/notification',
        headers: {
           'Authorization': 'key=' + serverKey,
           'project_id': senderId
        },
        body: {
           operation: 'create',
           notification_key_name: groupName,
           registration_ids: tokens
        },
        json: true
    };

    const resultRef = admin.database().ref('deviceGroup/create/result/key');

    return rqstProm(options)
        .then((parsedBody) => {
            console.log('SUCCESS response=', parsedBody);
            return resultRef.set(parsedBody.notification_key);
        })
        .catch((err) => {
            console.log('FAILED err=', err);
            return resultRef.set('ERROR: ' + err);
        });
});

使用云函数创 build 备组的示例代码(Android):

private ValueEventListener resultListener;

private void createDeviceGroup(String groupName, String ...deviceTokens) {
    final DatabaseReference baseRef =
            FirebaseDatabase.getInstance().getReference("deviceGroup/create");

    final DatabaseReference resultRef = baseRef.child("result");

    // listener to get the result of the group creation request
    resultListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snap) {
            if (snap.exists()) {
                // got the result; stop listening
                resultRef.removeEventListener(resultListener);
                String key = snap.child("key").getValue(String.class);
                Log.d(TAG, "createDeviceGroup: key=" + key);
            } else {
                // we get here when listener is first attached
                Log.w(TAG, "createDeviceGroup: No Result");
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            resultRef.removeEventListener(resultListener);
            throw databaseError.toException();
        }
    };

    // remove any previous result
    resultRef.removeValue();
    // start listening for a result
    resultRef.addValueEventListener(resultListener);

    // build the request params
    final Map<String,Object> request = new HashMap<>();
    final Map<String,Object> tokens = new HashMap<>();
    // creation of device group requires a name and set of tokens
    request.put("groupName", groupName);
    request.put("tokens", tokens);

    for (String token : deviceTokens) {
        // tokens are stored as keys; value is not significant
        tokens.put(token, true);
    }
    // write the request; this triggers Cloud Function to create device group
    baseRef.child("params").setValue(request);
}

这是成功创建组后的数据库布局:

{
  "deviceGroup": {
    "create": {
      "params": {
        "groupName": "testGroupA",
        "tokens": {
          "ccVDiSO1tbc:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true,
          "pqUYfyTbuax:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true,
          "tyKUY1mrUR8:APA91bE3pELSz...oDqY_ioLRj4xUnk5mci6ateFRVe" : true
        }
      },
      "result": {
        "key": "APA91bEY678qaLUAB1tOPv...tZ9IG64H7b0KtOo-hSJdsoovmuRe2eCyoUeu4qs"
      }
    }
  }
}  

关于swift - 创建 FCM 设备组返回 401,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44010135/

相关文章:

swift - “ fatal error :在展开可选值时意外发现nil”是什么意思?

ios - 如何防止变量被初始化两次?

ios - 未找到 GoogleService-Info.plist 文件且未以编程方式提供 clientId

firebase - 如何在应用程序离线时绕过 Firebase 身份验证?

ios - 使用 Firebase 函数将通知推送到群组

ios - Oauth 失败后的 AlamoFire 重试请求

ios - 如何使用 Swift 保持数据源与 firebase 实时数据库同步?

node.js - 部署错误 Node.js 8 ...函数部署出现以下函数错误 : dialogflowFirebaseFulfillment

c# - Unable install Xamarin Firebase - Common 32.961.0 to xamarin.forms解决方法

android - 我们如何通过使用 Firebase 云消息传递在 android 中进行推送通知来发送对象