Bezpieczne wypychanie w usłudze Azure Notification Hubs

Omówienie

Obsługa powiadomień wypychanych na platformie Microsoft Azure umożliwia dostęp do łatwej w użyciu, wieloplatformowej, skalowanej w poziomie infrastruktury wypychania, co znacznie upraszcza implementację powiadomień wypychanych zarówno dla aplikacji konsumenckich, jak i dla przedsiębiorstw dla platform mobilnych.

Ze względu na ograniczenia prawne lub ograniczenia zabezpieczeń czasami aplikacja może chcieć uwzględnić coś w powiadomieniu, którego nie można przekazać za pośrednictwem standardowej infrastruktury powiadomień wypychanych. W tym samouczku opisano sposób osiągnięcia tego samego środowiska przez wysyłanie poufnych informacji za pośrednictwem bezpiecznego, uwierzytelnionego połączenia między urządzeniem klienckim a zapleczem aplikacji.

Na wysokim poziomie przepływ jest następujący:

  1. Zaplecze aplikacji:
    • Przechowuje bezpieczny ładunek w bazie danych zaplecza.
    • Wysyła identyfikator tego powiadomienia do urządzenia (żadne bezpieczne informacje nie są wysyłane).
  2. Aplikacja na urządzeniu podczas odbierania powiadomienia:
    • Urządzenie kontaktuje się z zapleczem żądającym bezpiecznego ładunku.
    • Aplikacja może wyświetlić ładunek jako powiadomienie na urządzeniu.

Należy pamiętać, że w poprzednim przepływie (i w tym samouczku) przyjęto założenie, że urządzenie przechowuje token uwierzytelniania w magazynie lokalnym po zalogowaniu się użytkownika. Gwarantuje to bezproblemowe środowisko, ponieważ urządzenie może pobrać bezpieczny ładunek powiadomienia przy użyciu tego tokenu. Jeśli aplikacja nie przechowuje tokenów uwierzytelniania na urządzeniu lub jeśli te tokeny mogą zostać wygasłe, aplikacja urządzenia po otrzymaniu powiadomienia powinna wyświetlić ogólne powiadomienie z monitem użytkownika o uruchomienie aplikacji. Następnie aplikacja uwierzytelnia użytkownika i wyświetla ładunek powiadomień.

W tym samouczku dotyczącym bezpiecznego wypychania pokazano, jak bezpiecznie wysłać powiadomienie wypychane. Samouczek jest oparty na samouczku Powiadamianie użytkowników , dlatego najpierw należy wykonać kroki opisane w tym samouczku.

Uwaga

W tym samouczku założono, że centrum powiadomień zostało utworzone i skonfigurowane zgodnie z opisem w temacie Wysyłanie powiadomień wypychanych do aplikacji systemu iOS przy użyciu usługi Azure Notification Hubs.

Projekt WebAPI

  1. W programie Visual Studio otwórz projekt AppBackend utworzony w samouczku Powiadamianie użytkowników .

  2. W pliku Notifications.cs zastąp całą klasę Notifications następującym kodem. Pamiętaj, aby zastąpić symbole zastępcze parametrami połączenia (z pełnym dostępem) dla centrum powiadomień i nazwą centrum. Te wartości można uzyskać z Azure Portal. Ten moduł reprezentuje teraz różne bezpieczne powiadomienia, które zostaną wysłane. W pełnej implementacji powiadomienia będą przechowywane w bazie danych; dla uproszczenia w tym przypadku przechowujemy je w pamięci.

     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. W pliku NotificationsController.cs zastąp kod wewnątrz definicji klasy NotificationsController następującym kodem. Ten składnik implementuje sposób bezpiecznego pobierania powiadomienia przez urządzenie, a także umożliwia (na potrzeby tego samouczka) wyzwalanie bezpiecznego wypychania do urządzeń. Należy pamiętać, że podczas wysyłania powiadomienia do centrum powiadomień wysyłamy tylko nieprzetworzone powiadomienie z identyfikatorem powiadomienia (bez rzeczywistego komunikatu):

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

Pamiętaj, że Post metoda nie wysyła teraz wyskakujących powiadomień. Wysyła nieprzetworzone powiadomienie zawierające tylko identyfikator powiadomienia, a nie zawartość wrażliwą. Upewnij się również, że oznaczono jako komentarz operację wysyłania dla platform, dla których nie masz skonfigurowanych poświadczeń w centrum powiadomień, ponieważ spowodują one błędy.

  1. Teraz ponownie wdrożymy tę aplikację w witrynie internetowej platformy Azure, aby była dostępna ze wszystkich urządzeń. Kliknij prawym przyciskiem myszy projekt AppBackend i wybierz polecenie Publikuj.
  2. Wybierz pozycję Witryna internetowa platformy Azure jako element docelowy publikowania. Zaloguj się przy użyciu konta platformy Azure i wybierz istniejącą lub nową witrynę internetową i zanotuj właściwość docelowego adresu URL na karcie Połączenie . W dalszej części tego samouczka użyjemy tego adresu URL jako punktu końcowego zaplecza . Kliknij przycisk Opublikuj.

Modyfikowanie projektu systemu iOS

Po zmodyfikowaniu zaplecza aplikacji w celu wysłania tylko identyfikatora powiadomienia należy zmienić aplikację systemu iOS w celu obsługi tego powiadomienia i wywołania zaplecza w celu pobrania bezpiecznego komunikatu do wyświetlenia.

Aby osiągnąć ten cel, musimy napisać logikę w celu pobrania bezpiecznej zawartości z zaplecza aplikacji.

  1. W AppDelegate.msystemie upewnij się, że aplikacja rejestruje się w przypadku powiadomień dyskretnych, aby przetwarzała identyfikator powiadomienia wysyłanego z zaplecza. Dodaj opcję w pliku UIRemoteNotificationTypeNewsstandContentAvailability didFinishLaunchingWithOptions:

    [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeNewsstandContentAvailability];
    
  2. AppDelegate.m W sekcji dodawania implementacji u góry z następującą deklaracją:

    @interface AppDelegate ()
    - (void) retrieveSecurePayloadWithId:(int)payloadId completion: (void(^)(NSString*, NSError*)) completion;
    @end
    
  3. Następnie dodaj w sekcji implementacji następujący kod, zastępując symbol zastępczy {back-end endpoint} punktem końcowym uzyskanym wcześniej:

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

    Ta metoda wywołuje zaplecze aplikacji w celu pobrania zawartości powiadomień przy użyciu poświadczeń przechowywanych w udostępnionych preferencjach.

  4. Teraz obsłuż powiadomienie przychodzące i użyj metody powyżej, aby pobrać zawartość do wyświetlenia. Najpierw włącz uruchamianie aplikacji systemu iOS w tle podczas odbierania powiadomienia wypychanego. W programie XCode wybierz projekt aplikacji na panelu po lewej stronie, a następnie kliknij główny element docelowy aplikacji w sekcji Targets (Cele ) w okienku centralnym.

  5. Następnie kliknij kartę Możliwości w górnej części okienka centralnego i zaznacz pole Powiadomienia zdalne .

    Zrzut ekranu przedstawiający program XCode z wybranym projektem aplikacji i otwartą kartą Możliwości. Pole wyboru Powiadomienia zdalne jest zaznaczone.

  6. Dodaj AppDelegate.m następującą metodę do obsługi powiadomień wypychanych:

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

    Należy pamiętać, że zaleca się obsługę przypadków braku właściwości nagłówka uwierzytelniania lub odrzucenia przez zaplecze. Konkretna obsługa tych przypadków zależy głównie od środowiska użytkownika docelowego. Jedną z opcji jest wyświetlenie powiadomienia z ogólnym monitem o uwierzytelnienie użytkownika w celu pobrania rzeczywistego powiadomienia.

Uruchamianie aplikacji

Aby uruchomić aplikację, wykonaj następujące czynności:

  1. W programie XCode uruchom aplikację na fizycznym urządzeniu z systemem iOS (powiadomienia wypychane nie będą działać w symulatorze).
  2. W interfejsie użytkownika aplikacji systemu iOS wprowadź nazwę użytkownika i hasło. Może to być dowolny ciąg, ale muszą być tymi samymi wartościami.
  3. W interfejsie użytkownika aplikacji systemu iOS kliknij pozycję Zaloguj. Następnie kliknij pozycję Wyślij wypychanie. Powinno zostać wyświetlone bezpieczne powiadomienie w centrum powiadomień.