Push sicuro degli hub di notifica di AzureAzure Notification Hubs Secure Push

PanoramicaOverview

Il supporto per le notifiche push in Microsoft Azure consente di accedere a un'infrastruttura push di facile utilizzo, multipiattaforma con scalabilità orizzontale, che semplifica considerevolmente l'implementazione delle notifiche push sia per le applicazioni consumer sia per quelle aziendali per piattaforme mobili.Push notification support in Microsoft Azure enables you to access an easy-to-use, multiplatform, scaled-out push infrastructure, which greatly simplifies the implementation of push notifications for both consumer and enterprise applications for mobile platforms.

A causa di vincoli normativi o di sicurezza, un'applicazione potrebbe talvolta includere nella notifica informazioni che non è possibile trasmettere attraverso l'infrastruttura di notifiche push standard.Due to regulatory or security constraints, sometimes an application might want to include something in the notification that cannot be transmitted through the standard push notification infrastructure. In questa esercitazione viene descritto come conseguire la stessa esperienza inviando informazioni sensibili attraverso una connessione autenticata e sicura tra il dispositivo client e il back-end dell'app.This tutorial describes how to achieve the same experience by sending sensitive information through a secure, authenticated connection between the client device and the app backend.

A livello generale, il flusso è il seguente:At a high level, the flow is as follows:

  1. Il back-end dell'app:The app back-end:
    • Archivia il payload sicuro nel database back-end.Stores secure payload in back-end database.
    • Invia l'ID di questa notifica al dispositivo (non vengono inviate informazioni sicure).Sends the ID of this notification to the device (no secure information is sent).
  2. L'app sul dispositivo, quando riceve la notifica:The app on the device, when receiving the notification:
    • Il dispositivo contatta il back-end richiedendo il payload sicuro.The device contacts the back-end requesting the secure payload.
    • L'app può indicare il payload come una notifica sul dispositivo.The app can show the payload as a notification on the device.

È importante notare che nel flusso precedente e in questa esercitazione si presuppone che il dispositivo archivi un token di autenticazione nella memoria locale, dopo l’accesso dell'utente.It is important to note that in the preceding flow (and in this tutorial), we assume that the device stores an authentication token in local storage, after the user logs in. Ciò garantisce un'esperienza completamente lineare, in quanto il dispositivo può recuperare il payload sicuro della notifica tramite questo token.This guarantees a completely seamless experience, as the device can retrieve the notification’s secure payload using this token. Se invece l'applicazione non archivia i token di autenticazione nel dispositivo o se questi hanno una scadenza, l'app per dispositivo, alla ricezione della notifica, dovrà visualizzare una notifica generica in cui si richiede all'utente di avviare l'app.If your application does not store authentication tokens on the device, or if these tokens can be expired, the device app, upon receiving the notification should display a generic notification prompting the user to launch the app. L'app autentica quindi l'utente e mostra il payload di notifica.The app then authenticates the user and shows the notification payload.

In questa esercitazione sul push sicuro viene illustrato come inviare una notifica push in modo sicuro.This Secure Push tutorial shows how to send a push notification securely. Poiché i passaggi qui descritti si basano sull'esercitazione Utilizzo di Hub di notifica per inviare notifiche agli utenti , sarà prima necessario completare i passaggi di quest'ultima.The tutorial builds on the Notify Users tutorial, so you should complete the steps in that tutorial first.

Nota

In questa esercitazione si presuppone che l'utente abbia creato e configurato l'hub di notifica come descritto in Introduzione ad Hub di notifica (iOS).

Progetto WebAPIWebAPI Project

  1. In Visual Studio aprire il progetto AppBackend creato nell'esercitazione Notify Users (Inviare notifiche agli utenti).In Visual Studio, open the AppBackend project that you created in the Notify Users tutorial.
  2. In Notifications.cs sostituire l'intera classe Notifications con il codice seguente.In Notifications.cs, replace the whole Notifications class with the following code. Assicurarsi di sostituire i segnaposto con la stringa di connessione con accesso completo per l'hub di notifica e il nome dell'hub.Be sure to replace the placeholders with your connection string (with full access) for your notification hub, and the hub name. È possibile ottenere questi valori dal portale di Azure.You can obtain these values from the Azure portal. Questo modulo rappresenta ora le diverse notifiche sicure che verranno inviate.This module now represents the different secure notifications that will be sent. In un'implementazione completa le notifiche verranno archiviate in un database; per semplicità, in questo caso, verranno archiviate in memoria.In a complete implementation, the notifications will be stored in a database; for simplicity, in this case we store them in memory.

     public class Notification
     {
         public int Id { get; set; }
         public string Payload { get; set; }
         public bool Read { get; set; }
     }
    
     public class Notifications
     {
         public static Notifications Instance = new Notifications();
    
         private List<Notification> notifications = new List<Notification>();
    
         public NotificationHubClient Hub { get; set; }
    
         private Notifications() {
             Hub = NotificationHubClient.CreateClientFromConnectionString("{conn string with full access}",     "{hub name}");
         }
    
         public Notification CreateNotification(string payload)
         {
             var notification = new Notification() {
             Id = notifications.Count,
             Payload = payload,
             Read = false
             };
    
             notifications.Add(notification);
    
             return notification;
         }
    
         public Notification ReadNotification(int id)
         {
             return notifications.ElementAt(id);
         }
     }
    
  3. In NotificationsController.cs sostituire il codice all'interno della definizione della classe NotificationsController con il codice seguente.In NotificationsController.cs, replace the code inside the NotificationsController class definition with the following code. Questo componente implementa un modo per il recupero della notifica da parte del dispositivo. Inoltre, ai fini di questa esercitazione, fornisce all'utente un modo per attivare un push sicuro ai propri dispositivi.This component implements a way for the device to retrieve the notification securely, and also provides a way (for the purposes of this tutorial) to trigger a secure push to your devices. Notare che a Hub di notifica verrà inviata una notifica non elaborata, che contiene l'ID della notifica senza alcun messaggio:Note that when sending the notification to the notification hub, we only send a raw notification with the ID of the notification (and no actual message):

    public NotificationsController()
    {
        Notifications.Instance.CreateNotification("This is a secure notification!");
    }
    
    // GET api/notifications/id
    public Notification Get(int id)
    {
        return Notifications.Instance.ReadNotification(id);
    }
    
    public async Task<HttpResponseMessage> Post()
    {
        var secureNotificationInTheBackend = Notifications.Instance.CreateNotification("Secure confirmation.");
        var usernameTag = "username:" + HttpContext.Current.User.Identity.Name;
    
        // windows
        var rawNotificationToBeSent = new Microsoft.Azure.NotificationHubs.WindowsNotification(secureNotificationInTheBackend.Id.ToString(),
                        new Dictionary<string, string> {
                            {"X-WNS-Type", "wns/raw"}
                        });
        await Notifications.Instance.Hub.SendNotificationAsync(rawNotificationToBeSent, usernameTag);
    
        // apns
        await Notifications.Instance.Hub.SendAppleNativeNotificationAsync("{\"aps\": {\"content-available\": 1}, \"secureId\": \"" + secureNotificationInTheBackend.Id.ToString() + "\"}", usernameTag);
    
        // gcm
        await Notifications.Instance.Hub.SendGcmNativeNotificationAsync("{\"data\": {\"secureId\": \"" + secureNotificationInTheBackend.Id.ToString() + "\"}}", usernameTag);
    
         return Request.CreateResponse(HttpStatusCode.OK);
     }
    

Notare che il metodo Post non invia ora una notifica di tipo avviso popup,Note that the Post method now does not send a toast notification. ma una notifica non elaborata che contiene solo l'ID notifica e non contenuto sensibile.It sends a raw notification that contains only the notification ID, and not any sensitive content. Assicurarsi inoltre di impostare come commento l'operazione send per le piattaforme per le quali non sono configurate le credenziali nell'hub di notifica, in caso contrario verranno restituiti errori.Also, make sure to comment the send operation for the platforms for which you do not have credentials configured on your notification hub, as they will result in errors.

  1. L'app verrà ora nuovamente distribuita in un sito Web di Azure in modo da renderla accessibile da tutti i dispositivi.Now we will re-deploy this app to an Azure Website in order to make it accessible from all devices. Fare clic con il pulsante destro del mouse sul progetto AppBackend e scegliere Pubblica.Right-click on the AppBackend project and select Publish.
  2. Selezionare un sito Web Azure come destinazione di pubblicazione.Select Azure Website as your publish target. Accedere con l'account di Azure e selezionare un sito Web nuovo o esistente, quindi prendere nota della proprietà URL di destinazione nella scheda Connessione. Si farà riferimento a quest'URL come endpoint back-end più avanti in questa esercitazione.Log in with your Azure account and select an existing or new Website, and make a note of the destination URL property in the Connection tab. We will refer to this URL as your backend endpoint later in this tutorial. Fare clic su Pubblica.Click Publish.

Modifica del progetto iOSModify the iOS project

Ora che è stato modificato il back-end dell'app in modo da inviare solo l' ID di una notifica, è necessario modificare l'app per iOS in modo da gestire tale notifica e richiamare il back-end per recuperare il messaggio sicuro da visualizzare.Now that you modified your app back-end to send just the id of a notification, you have to change your iOS app to handle that notification and call back your back-end to retrieve the secure message to be displayed.

Per conseguire questo obiettivo, è necessario scrivere la logica per recuperare il contenuto sicuro dal back-end dell'app.To achieve this goal, we have to write the logic to retrieve the secure content from the app back-end.

  1. In AppDelegate.massicurarsi che l'app esegua la registrazione per le notifiche silenziose in modo da elaborare l'ID della notifica inviato dal back-end.In AppDelegate.m, make sure the app registers for silent notifications so it processes the notification id sent from the backend. Aggiungere l'opzione UIRemoteNotificationTypeNewsstandContentAvailability in didFinishLaunchingWithOptions:Add the UIRemoteNotificationTypeNewsstandContentAvailability option in didFinishLaunchingWithOptions:

     [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeNewsstandContentAvailability];
    
  2. In AppDelegate.m aggiungere una sezione di implementazione in alto con la dichiarazione seguente:In your AppDelegate.m add an implementation section at the top with the following declaration:

     @interface AppDelegate ()
     - (void) retrieveSecurePayloadWithId:(int)payloadId completion: (void(^)(NSString*, NSError*)) completion;
     @end
    
  3. Aggiungere quindi la sezione di implementazione al seguente codice, sostituendo il segnaposto {back-end endpoint} con l'endpoint per il back-end ottenuto in precedenza:Then add in the implementation section the following code, substituting the placeholder {back-end endpoint} with the endpoint for your back-end obtained previously:
        NSString *const GetNotificationEndpoint = @"{back-end endpoint}/api/notifications";

        - (void) retrieveSecurePayloadWithId:(int)payloadId completion: (void(^)(NSString*, NSError*)) completion;
        {
            // check if authenticated
            ANHViewController* rvc = (ANHViewController*) self.window.rootViewController;
            NSString* authenticationHeader = rvc.registerClient.authenticationHeader;
            if (!authenticationHeader) return;


            NSURLSession* session = [NSURLSession
                                     sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                     delegate:nil
                                     delegateQueue:nil];


            NSURL* requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%d", GetNotificationEndpoint, payloadId]];
            NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL];
            [request setHTTPMethod:@"GET"];
            NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@", authenticationHeader];
            [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"];

            NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
                if (!error && httpResponse.statusCode == 200)
                {
                    NSLog(@"Received secure payload: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

                    NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &error];

                    completion([json objectForKey:@"Payload"], nil);
                }
                else
                {
                    NSLog(@"Error status: %ld, request: %@", (long)httpResponse.statusCode, error);
                    if (error)
                        completion(nil, error);
                    else {
                        completion(nil, [NSError errorWithDomain:@"APICall" code:httpResponse.statusCode userInfo:nil]);
                    }
                }
            }];
            [dataTask resume];
        }
This method calls your app back-end to retrieve the notification content using the credentials stored in the shared preferences.
  1. A questo punto, è necessario gestire la notifica in arrivo e usare il metodo sopra citato per recuperare il contenuto da visualizzare.Now we have to handle the incoming notification and use the method above to retrieve the content to display. In primo luogo, è necessario abilitare l'esecuzione dell'app per iOS in background quando riceve una notifica push.First, we have to enable your iOS app to run in the background when receiving a push notification. In XCode selezionare il progetto dell'app nel riquadro a sinistra, fare clic sull'app di destinazione principale nella sezione Targets (Destinazioni) nel riquadro centrale.In XCode, select your app project on the left panel, then click your main app target in the Targets section from the central pane.
  2. Fare quindi clic sulla scheda Capabilities (Funzionalità) nella parte superiore del riquadro centrale e selezionare la casella di controllo Remote Notifications (Notifiche remote).Then click your Capabilities tab at the top of your central pane, and check the Remote Notifications checkbox.

  3. In AppDelegate.m aggiungere il metodo seguente per gestire le notifiche push:In AppDelegate.m add the following method to handle push notifications:

     -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
     {
         NSLog(@"%@", userInfo);
    
         [self retrieveSecurePayloadWithId:[[userInfo objectForKey:@"secureId"] intValue] completion:^(NSString * payload, NSError *error) {
             if (!error) {
                 // show local notification
                 UILocalNotification* localNotification = [[UILocalNotification alloc] init];
                 localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
                 localNotification.alertBody = payload;
                 localNotification.timeZone = [NSTimeZone defaultTimeZone];
                 [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    
                 completionHandler(UIBackgroundFetchResultNewData);
             } else {
                 completionHandler(UIBackgroundFetchResultFailed);
             }
         }];
    
     }
    

    Notare che è preferibile gestire i casi in cui manca la proprietà dell'intestazione di autenticazione o di rifiuto da parte del back-end.Note that it is preferable to handle the cases of missing authentication header property or rejection by the back-end. La gestione specifica di questi casi dipende in larga misura dall'esperienza dell'utente di destinazione.The specific handling of these cases depend mostly on your target user experience. Una delle opzioni consiste nel visualizzare una notifica con un prompt generico affinché l'utente possa autenticarsi per recuperare la notifica effettiva.One option is to display a notification with a generic prompt for the user to authenticate to retrieve the actual notification.

Eseguire l'applicazioneRun the Application

Per eseguire l'applicazione, eseguire le operazioni seguenti:To run the application, do the following:

  1. In XCode eseguire l'app su un dispositivo iOS fisico (le notifiche push non funzioneranno nel simulatore).In XCode, run the app on a physical iOS device (push notifications will not work in the simulator).
  2. Nell'interfaccia utente dell'app per iOS immettere un nome utente e una password.In the iOS app UI, enter a username and password. Può trattarsi di qualsiasi stringa, ma devono avere lo stesso valore.These can be any string, but they must be the same value.
  3. Nell'interfaccia utente dell'app per iOS fare clic su Log in.In the iOS app UI, click Log in. Fare clic su Send push.Then click Send push. La notifica sicura verrà visualizzata nel Notification Center.You should see the secure notification being displayed in your notification center.