创建FCM设备组返回401

时间:2017-05-16 19:36:26

标签: swift firebase firebase-cloud-messaging

我正在尝试为我的一个用户创建一个FCM设备组,但在发布create请求时,我得到401 reponse code

以下是我的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")
        }
    }

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

1 个答案:

答案 0 :(得分:2)

在此声明中:

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

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

您在评论中表明您是从客户端设备执行此操作。将服务器密钥放入设备代码中并不安全。

更安全的替代方法是在云功能中执行设备组创建。以下是通过将组创建参数存储在数据库中而触发的基本实现。仅举例;未彻底测试;更正/评论欢迎。

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);
        });
});

使用云功能创建设备组的示例代码(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"
      }
    }
  }
}