Invio di notifiche push sicure con Hub di notifica di AzureSending Secure Push Notifications with Azure Notification Hubs

OverviewOverview

Importante

Per completare l'esercitazione, è necessario disporre di un account Azure attivo.To complete this tutorial, you must have an active Azure account. Se non si dispone di un account, è possibile creare un account di valutazione gratuita in pochi minuti.If you don't have an account, you can create a free trial account in just a couple of minutes. Per informazioni dettagliate, vedere la pagina relativa alla versione di valutazione gratuita di Azure.For details, see Azure Free Trial.

Il supporto per le notifiche push in Microsoft Azure consente di accedere a un'infrastruttura di messaggistica 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 message 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. Questa esercitazione descrive come conseguire la stessa esperienza inviando informazioni sensibili attraverso una connessione autenticata e sicura tra il dispositivo client Android 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 Android 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 Android (non vengono inviate informazioni sicure).Sends the ID of this notification to the Android 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 Android contatta il back-end richiedendo il payload sicuro.The Android 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 push, 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 push 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.

Questa esercitazione descrive come inviare notifiche push sicure.This tutorial shows how to send secure push notifications. Poiché i passaggi descritti in questa esercitazione si basano su quella relativa all' invio di notifiche agli utenti , sarà prima necessario completare i passaggi di quest'ultima.It builds on the Notify Users tutorial, so you should complete the steps in that tutorial first if you haven't already.

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 (Android).This tutorial assumes that you have created and configured your notification hub as described in Getting Started with Notification Hubs (Android).

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 classico.You can obtain these values from the Azure Classic 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.

Modificare il progetto AndroidModify the Android project

Ora che è stato modificato il back-end dell'app in modo da inviare solo l' ID di una notifica push, è necessario modificare l'app per Android 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 push notification, you have to change your Android app to handle that notification and call back your back-end to retrieve the secure message to be displayed. Per conseguire questo obiettivo, è necessario assicurarsi che l'app per Android sia in grado di eseguire l'autenticazione con il back-end quando riceve le notifiche push.To achieve this goal, you have to make sure that your Android app knows how to authenticate itself with your back-end when it receives the push notifications.

Ora si modificherà il flusso di accesso per salvare il valore dell'intestazione di autenticazione nelle preferenze condivise dell'app.We will now modify the login flow in order to save the authentication header value in the shared preferences of your app. Un meccanismo analogo può essere usato per archiviare eventuali token di autenticazione (ad esempio token OAuth) che l'app dovrà usare senza richiedere le credenziali dell'utente.Analogous mechanisms can be used to store any authentication token (e.g. OAuth tokens) that the app will have to use without requiring user credentials.

  1. Nel progetto di app per Android, aggiungere le costanti seguenti all'inizio della classe MainActivity :In your Android app project, add the following constants at the top of the MainActivity class:

     public static final String NOTIFY_USERS_PROPERTIES = "NotifyUsersProperties";
     public static final String AUTHORIZATION_HEADER_PROPERTY = "AuthorizationHeader";
    
  2. Sempre nella classe MainActivity aggiornare il metodo getAuthorizationHeader() per includere il codice seguente:Still in the MainActivity class, update the getAuthorizationHeader() method to contain the following code:

     private String getAuthorizationHeader() throws UnsupportedEncodingException {
         EditText username = (EditText) findViewById(R.id.usernameText);
         EditText password = (EditText) findViewById(R.id.passwordText);
         String basicAuthHeader = username.getText().toString()+":"+password.getText().toString();
         basicAuthHeader = Base64.encodeToString(basicAuthHeader.getBytes("UTF-8"), Base64.NO_WRAP);
    
         SharedPreferences sp = getSharedPreferences(NOTIFY_USERS_PROPERTIES, Context.MODE_PRIVATE);
         sp.edit().putString(AUTHORIZATION_HEADER_PROPERTY, basicAuthHeader).commit();
    
         return basicAuthHeader;
     }
    
  3. Aggiungere le seguenti istruzioni import all'inizio del file MainActivity :Add the following import statements at the top of the MainActivity file:

     import android.content.SharedPreferences;
    

A questo punto, modificare il gestore chiamato quando si riceve la notifica.Now we will change the handler that is called when the notification is received.

  1. Nella classe MyHandler modificare il metodo OnReceive() in modo che contenga:In the MyHandler class change the OnReceive() method to contain:

     public void onReceive(Context context, Bundle bundle) {
         ctx = context;
         String secureMessageId = bundle.getString("secureId");
         retrieveNotification(secureMessageId);
     }
    
  2. Aggiungere quindi il metodo retrieveNotification(), sostituendo il segnaposto {back-end endpoint} con l'endpoint del back-end ottenuto durante la distribuzione del back-end:Then add the retrieveNotification() method, replacing the placeholder {back-end endpoint} with the back-end endpoint obtained while deploying your back-end:

     private void retrieveNotification(final String secureMessageId) {
         SharedPreferences sp = ctx.getSharedPreferences(MainActivity.NOTIFY_USERS_PROPERTIES, Context.MODE_PRIVATE);
         final String authorizationHeader = sp.getString(MainActivity.AUTHORIZATION_HEADER_PROPERTY, null);
    
         new AsyncTask<Object, Object, Object>() {
             @Override
             protected Object doInBackground(Object... params) {
                 try {
                     HttpUriRequest request = new HttpGet("{back-end endpoint}/api/notifications/"+secureMessageId);
                     request.addHeader("Authorization", "Basic "+authorizationHeader);
                     HttpResponse response = new DefaultHttpClient().execute(request);
                     if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                         Log.e("MainActivity", "Error retrieving secure notification" + response.getStatusLine().getStatusCode());
                         throw new RuntimeException("Error retrieving secure notification");
                     }
                     String secureNotificationJSON = EntityUtils.toString(response.getEntity());
                     JSONObject secureNotification = new JSONObject(secureNotificationJSON);
                     sendNotification(secureNotification.getString("Payload"));
                 } catch (Exception e) {
                     Log.e("MainActivity", "Failed to retrieve secure notification - " + e.getMessage());
                     return e;
                 }
                 return null;
             }
         }.execute(null, null, null);
     }
    

Questo metodo chiama il back-end dell'app per recuperare il contenuto della notifica usando le credenziali memorizzate nelle preferenze condivise e lo visualizza come una normale notifica.This method calls your app back-end to retrieve the notification content using the credentials stored in the shared preferences and displays it as a normal notification. L'utente dell'app vedrà la notifica esattamente come qualsiasi altra notifica push.The notification looks to the app user exactly like any other push notification.

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.

Esecuzione dell'applicazioneRun the Application

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

  1. Assicurarsi che il progetto AppBackend sia distribuito in Azure.Make sure AppBackend is deployed in Azure. Se si usa Visual Studio, eseguire l'applicazione API Web AppBackend .If using Visual Studio, run the AppBackend Web API application. Verrà visualizzata una pagina Web ASP.NET.An ASP.NET web page is displayed.
  2. In Eclipse eseguire l'app su un dispositivo Android fisico o sull'emulatore.In Eclipse, run the app on a physical Android device or the emulator.
  3. Nell'interfaccia utente dell'app per Android immettere un nome utente e una password.In the Android 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.
  4. Nell'interfaccia utente dell'app per Android fare clic su Log in.In the Android app UI, click Log in. Fare clic su Send push.Then click Send push.