C#Firebase Cloud Message使用主题消息发送多个Web JS通知

时间:2019-05-02 09:12:23

标签: c# firebase firebase-cloud-messaging

我尝试使用主题发送多个Web通知,而不是循环向每个令牌发送通知。

但是我坚持使用401 unauthorized的凭据使用主题发送通知给主题

这是我的代码

首先,我通过以下Firebase示例代码:https://github.com/firebase/quickstart-js/blob/master/messaging

请求Web浏览器获得通知令牌的权限

index.html上,我更改了这样的代码以将令牌发送到服务器以订阅主题

    function resetUI() {
        clearMessages();

        // [START get_token]
        // Get Instance ID token. Initially this makes a network call, once retrieved
        // subsequent calls to getToken will return from cache.
        messaging.getToken().then(function (currentToken) {
            if (currentToken) {
                console.log("Get Token OK: " + currentToken);
                sendTokenToServer(currentToken);
            } else {
                // Show permission request.
                console.log('No Instance ID token available. Request permission to generate one.');
                // Reset Token on Server to False
                setTokenSentToServer(false);

                // Request permission for Token
                requestPermission();
            }
        }).catch(function (err) {
            console.log('An error occurred while retrieving token. ', err);

            setTokenSentToServer(false);
        });
        // [END get_token]
    }


    // Send the Instance ID token your application server, so that it can:
    // - send messages back to this app
    // - subscribe/unsubscribe the token from topics
    function sendTokenToServer(currentToken) {
        if (!(window.localStorage.getItem('EDXNotificationIsSentToServer') === '1')) {
            console.log('Sending token to server...');

            var tokenObject = {
                token: currentToken
            };

            $.ajax({
                type: "POST",
                url: '@Url.Action("SaveToken", "Api")',
                data: JSON.stringify(tokenObject),
                contentType: "application/json; charset=utf-8",
                success: function (data) {
                    if (data) {
                        // TODO(developer): Send the current token to your server.
                        setTokenSentToServer(true);
                    }
                },
                complete: function (status) {
                },
                error: function (error) { }
            });

        } else {
            console.log('Token already sent to server so won\'t send it again unless it changes');
        }

    }

在服务器上,我将令牌存储到数据库中并订阅了测试主题

    public class ApiController : Controller
    {
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Lưu token
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public JsonResult SaveToken(TBL_Customer_Tokens model)
        {
            try
            {
                if (!string.IsNullOrEmpty(model.token))
                {
                    bool ret = true;

                    if(GCMUtils.SubcribeTokenToTopic(model.token, ConfigurationManager.AppSettings["GCMTopic"]))
                        ret = DataServiceFactory.GetCustomerService().SaveToken(model.token); // Save token to database, don't care about this function. It is ok

                    if (ret)
                        Json(true, JsonRequestBehavior.AllowGet);
                }
            }
            catch (Exception ex)
            {
                log.Debug(ex.Message, ex);
            }

            return Json(false, JsonRequestBehavior.AllowGet);
        }
    }

这是GCMUtils

    public class GCMUtils
    {
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


        public static bool SubcribeTokenToTopic(string token, string topic)
        {
            try
            {
                string url = String.Format("https://iid.googleapis.com/iid/v1/{0}/rel/topics/{1}", token, topic);

                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);

                req.ContentType = "application/json";
                req.Headers.Add("Authorization", "key=" + ConfigurationManager.AppSettings["GCMServerKey"]);


                req.Method = "POST";
                req.ContentLength = 0;

                Stream reqStream = req.GetRequestStream();
                reqStream.Close();

                HttpWebResponse response = (HttpWebResponse)req.GetResponse();

                if (response.StatusCode == HttpStatusCode.OK)
                    return true;
            }
            catch (Exception ex)
            {
                log.Debug(ex.Message, ex);
            }

            return false;
        }
    }

检索令牌,将其保存到数据库并成功订阅主题。 因此您可以忽略上面的代码,仅分析下面的问题

其次,我正尝试向主题发送网络通知,而不是向每个令牌https://firebase.google.com/docs/cloud-messaging/js/topic-messaging发送单个通知

    public static bool SendFirebaseTopicNotificationAsync(string topicSubscription, NotificationPayload dat)
    {
        try
        {
            List<string> scopes = new List<string>();
            scopes.Add("https://www.googleapis.com/auth/firebase");
            scopes.Add("https://www.googleapis.com/auth/firebase.messaging");

            string accesstoken = GoogleCredential.FromFile(ConfigurationManager.AppSettings["GoogleCredentialFilePath"])
                                                        .CreateScoped(scopes)
                                                        .UnderlyingCredential
                                                        .GetAccessTokenForRequestAsync().Result;

            WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/v1/projects/test-project/messages:send");
            tRequest.Method = "post";


            tRequest.Headers.Add("Authorization", "bearer " + accesstoken);
            tRequest.ContentType = "application/json";

            var payload = new
            {
                message = new
                {
                    topic = topicSubscription,
                    notification = new {
                        title = dat.title,
                        body = dat.body
                    },
                    webpush = new
                    {
                        fcm_options = new {
                            link = dat.click_action
                        }
                    }
                }
            };

            string postbody = JsonConvert.SerializeObject(payload).ToString();
            Byte[] byteArray = Encoding.UTF8.GetBytes(postbody);
            tRequest.ContentLength = byteArray.Length;
            using (Stream dataStream = tRequest.GetRequestStream())
            {
                dataStream.Write(byteArray, 0, byteArray.Length);
                using (WebResponse tResponse = tRequest.GetResponse())
                {
                    using (Stream dataStreamResponse = tResponse.GetResponseStream())
                    {
                        if (dataStreamResponse != null) using (StreamReader tReader = new StreamReader(dataStreamResponse))
                            {
                                String sResponseFromServer = tReader.ReadToEnd();
                                Console.WriteLine(sResponseFromServer);

                                return true;
                            }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            log.Debug(ex.Message, ex);
        }

        return false;
    }

请注意,test-project中的SendFirebaseTopicNotificationAsync是项目名称。我确定这是真的

ConfigurationManager.AppSettings["GoogleCredentialFilePath"]是.json密钥文件的绝对文件路径,我正在遵循此准则来检索https://www.c-sharpcorner.com/article/retrieve-access-token-for-google-service-account-form-json-or-p12-key-in-c-sharp/

但是我收到401 Unauthorized错误。似乎来自GoogleCredential的访问令牌是错误的

任何帮助将不胜感激

谢谢

1 个答案:

答案 0 :(得分:0)

这是这行的愚蠢错误

IPOINT_BEFORE

tRequest.Headers.Add("Authorization", "bearer " + accesstoken); 是错误的,请改用bearer

Bearer

我还发现了这篇文章https://github.com/googleapis/google-api-dotnet-client/issues/1140

这家伙也有 tRequest.Headers.Add("Authorization", "Bearer " + accesstoken); 。但是他的问题与我不同。他未在Google Cloud Platform中启用FCM API https://console.cloud.google.com/apis/dashboard

相关问题