403 尝试使用 Azure 通知中心批量发送时被禁止

杰米

我正在尝试使用批量发送 API 端点根据他们的兴趣向特定用户发送大量推送通知。我们已经得出结论,通知中心中的标签系统没有提供我们需要的灵活性。

我有一个数据库,用于存储可由直接发送端点使用的设备令牌,但即使使用 Microsoft 提供的标准信息,也会提供 403 错误,但没有任何关于出错的信息。

public class WnsNotificationService : BaseNotificationService
{
    private ISubscriptionProvider subscriptionProvider;

    /// <summary>
    /// Initializes a new instance of the <see cref="WnsNotificationService" /> class.
    /// </summary>
    /// <param name="telemetryService">The telemetry service.</param>
    /// <param name="subscriptionProvider">The subscription provider.</param>
    public WnsNotificationService(ITelemetryService telemetryService, ISubscriptionProvider subscriptionProvider) : base(telemetryService)
    {
        this.subscriptionProvider = subscriptionProvider;
    }

    /// <summary>
    /// Sends the new Airport Event notification to windows devices via WNS.
    /// </summary>
    /// <param name="airportEvent">The Airport Event.</param>
    /// <returns>
    /// Notification Result
    /// </returns>
    public override async Task<NotificationResult> SendNotification(AirportEvent airportEvent)
    {
        try
        {
            IEnumerable<IEnumerable<string>> deviceCollection =
                this.subscriptionProvider.GetSubscribedUserPNSHandles(airportEvent, PushNotificationPlatform.wns).Batch(1000);

            foreach (var devices in deviceCollection)
            {
                ServiceBusConnectionStringBuilder connectionString = new ServiceBusConnectionStringBuilder(ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.ConnectionString"]);
                string serviceBusNamespace = connectionString.Endpoints.First().Host;
                string namespaceKeyName = connectionString.SharedAccessKeyName;
                string namespaceKey = connectionString.SharedAccessKey;

                var uri = new Uri($"{ ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.Url"] }/{ ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.HubName"] }/messages/$batch?direct&api-version=2015-08");
                var request = WebRequest.CreateHttp(uri);
                request.Method = "POST";
                request.ContentType = @"multipart/mixed; boundary = ""simple-boundary""";
                request.Headers["Authorization"] = SharedAccessSignatureTokenProvider.GetSharedAccessSignature(namespaceKeyName, namespaceKey, serviceBusNamespace, TimeSpan.FromMinutes(45));
                request.Headers["ServiceBusNotification-Format"] = "windows";
                request.Headers["X-WNS-Type"] = "wns/raw";

                string body = this.GenerateBatchRequestBody(airportEvent.AirportEventId, devices);

                byte[] requestBytes = new ASCIIEncoding().GetBytes(body);
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(requestBytes, 0, requestBytes.Length);

                request.GetResponse();
            }

            return new NotificationResult(true);
        }
        catch (Exception)
        {
            return new NotificationResult(false);
        }
    }

    /// <summary>
    /// Sends the new Airport Event notification to a specific windows device via WNS.
    /// </summary>
    /// <param name="deviceId">The device identifier.</param>
    /// <param name="airportEvent">The Airport Event.</param>
    /// <returns>
    /// Notification Result
    /// </returns>
    /// <exception cref="System.NotImplementedException">Not Implemented Exception</exception>
    public override Task<NotificationResult> SendNotificationToDevice(string deviceId, AirportEvent airportEvent)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Generates the batch request body.
    /// </summary>
    /// <param name="airportEventGuid">The airport event unique identifier.</param>
    /// <param name="devices">The devices.</param>
    /// <returns>Request Body</returns>
    private string GenerateBatchRequestBody(Guid airportEventGuid, IEnumerable<string> devices)
    {
        return @"
--simple-boundary
Content-type: text/xml
Content-Disposition: inline; name=notification

<toast><visual><binding template=""ToastText01""><text id=""1"">Hello from 
Batch Direct Send!</text></binding></visual></toast>
--simple-boundary
Content-type: application/json
Content-Disposition: inline; name=devices

['https://{foo}.notify.windows.com/?token={bar}']
--simple-boundary--";
    }
}

这是使用https://azure.microsoft.com/en-us/blog/push-notification-hubs-batch-direct-send/提供的信息

陈小龙

根据您的描述,我检查了直接批量发送并按照此示例azure-notificationhubs-samples在我这边测试了这个问题。经过一些试验,我可以让它在我身边工作,如下所示:

在此处输入图片说明

根据您的代码,我假设您需要更改request.Headers["X-WNS-Type"] = "wns/raw";request.Headers["X-WNS-Type"] = "wns/toast";,并且您的授权令牌可能无效。这是我生成授权令牌的方法,您可以参考:

/// <summary>
/// GetSharedAccessSignature
/// </summary>
/// <param name="SasKeyName">SharedAccessKeyName</param>
/// <param name="SasKeyValue">SharedAccessKey</param>
/// <param name="uri">resourceURI (e.g. https://{namespace}.servicebus.windows.net/{NotificationHub}/messages/$batch?direct&api-version=2015-08)</param>
/// <param name="minUntilExpire">minUntilExpire</param>
/// <returns></returns>
private static string GetSharedAccessSignature(string SasKeyName, string SasKeyValue, string uri, TimeSpan minUntilExpire)
{
    string targetUri = Uri.EscapeDataString(uri.ToLower()).ToLower();

    // Add an expiration in seconds to it.
    long expiresOnDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
    expiresOnDate += (long)minUntilExpire.TotalMilliseconds;
    long expires_seconds = expiresOnDate / 1000;
    String toSign = targetUri + "\n" + expires_seconds;

    // Generate a HMAC-SHA256 hash or the uri and expiration using your secret key.
    byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(SasKeyValue);
    HMACSHA256 hmacsha256 = new HMACSHA256(keyBytes);
    byte[] hash = hmacsha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toSign));

    // Create the token string using the base64
    string signature = Uri.EscapeDataString(Convert.ToBase64String(hash));

    return "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires_seconds + "&skn=" + SasKeyName;
}

注:下面是官方的代码示例,你可以参考

此外,由于直接批量发送状态如下:

将一批通知直接发送到一组设备句柄(由 Notification 类型表示的有效令牌)。此 API 可用于基本和标准层通知中心命名空间

您需要将定价层更改为 Basic 或 Standard,否则您将通过Fiddler获得以下响应

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Azure存储-禁止使用403

尝试使用CORS时获取403(禁止)

使用Azure发布时禁止使用HTTP 403

使用Google Photos API时被禁止使用403

在Azure门户中测试网络聊天时,新的Bot频道注册被禁止使用403

尝试释放 Azure 容器租约时出现 403 授权错误

已部署的网站被禁止使用403

使用 angular-azure-blob-service 时出现 403 错误

通过SAS访问Azure Blob存储时禁止使用零散403

403使用Cheerio时禁止

错误:无法下载视频数据:HTTP错误403:使用youtube_dl时被禁止

当使用Keyclaok进行POST请求时,Spring Boot返回403被禁止

HTTP错误403:使用urllib下载文件时被禁止

错误403尝试通过Active Directory访问Azure Databricks API时未授权用户

尝试通过Azure网站管理REST API列出网站空间时为403

尝试使用Google Cloud Speech API时抛出403

尝试使用 Firebase 登录时出现 403:restricted_client

尝试使用KV时,Hashicorp Vault cli CLI返回403

尝试使用TinyMCE上传图像时出现错误403

尝试从另一个网站打开网站上的网页时被禁止 403

Azure CloudBlobContainer.CreateIfNotExists返回403禁止

403 在laravel 8 形式中使用@csrf 後被禁止

Bootstrap 3图示符被禁止使用403

尝试向 Azure 通知中心注册设备时出错

HTTP错误403:使用NLTK时禁止

403禁止,尝试一切

安装Azure Pack Express时的HTTP 403

尝试进行身份验证时出现403禁止错误

尝试从Pod访问Kubernetes API时出现403禁止错误