Szybki start: inicjowanie aplikacji klienckiej (C++)

W tym przewodniku Szybki start pokazano, jak zaimplementować wzorzec inicjowania klienta używany przez zestaw MIP C++ SDK w czasie wykonywania.

Uwaga

Kroki opisane w tym przewodniku Szybki start są wymagane dla każdej aplikacji klienckiej korzystającej z zestawów SDK plików, zasad lub ochrony programu MIP. Mimo że w tym przewodniku Szybki start pokazano użycie zestawów SDK plików, ten sam wzorzec ma zastosowanie do klientów korzystających z zestawów SDK zasad i ochrony. Ukończ pozostałe przewodniki Szybki start szeregowo, ponieważ każda z nich jest oparta na poprzedniej, a ta jest pierwszą.

Wymagania wstępne

Jeśli jeszcze tego nie zrobiono, upewnij się, że:

  • Wykonaj kroki opisane w artykule Konfiguracja i konfiguracja zestawu SDK usługi Microsoft Information Protection (MIP). Ten przewodnik Szybki start "Inicjowanie aplikacji klienckiej" opiera się na odpowiedniej konfiguracji i konfiguracji zestawu SDK.
  • Opcjonalnie:
    • Przejrzyj obiekty profilu i aparatu. Obiekty profilu i aparatu są uniwersalnymi pojęciami wymaganymi przez klientów korzystających z zestawów SDK plików/zasad/ochrony miP.
    • Zapoznaj się z pojęciami dotyczącymi uwierzytelniania, aby dowiedzieć się, jak uwierzytelnianie i zgoda są implementowane przez zestaw SDK i aplikację kliencą.
    • Zapoznaj się z pojęciami obserwatora , aby dowiedzieć się więcej na temat obserwatorów i sposobu ich implementacji. Zestaw MIP SDK używa wzorca obserwatora do implementowania asynchronicznych powiadomień o zdarzeniach.

Tworzenie rozwiązania i projektu programu Visual Studio

Najpierw utworzymy i skonfigurujemy początkowe rozwiązanie i projekt programu Visual Studio, na którym kompilujemy inne przewodniki Szybki start.

  1. Otwórz program Visual Studio 2017, wybierz menu Plik , Nowy, Projekt. W oknie dialogowym Nowy projekt:

    • W okienku po lewej stronie w obszarze Zainstalowane inne języki wybierz pozycję Visual C++.

    • W środkowym okienku wybierz pozycję Aplikacja konsolowa systemu Windows

    • W dolnym okienku zaktualizuj odpowiednio nazwę projektu, lokalizację i nazwę rozwiązania zawierającego.

    • Po zakończeniu kliknij przycisk OK w prawym dolnym rogu.

      Visual Studio solution creation

  2. Dodaj pakiet Nuget dla zestawu MIP File SDK do projektu:

    • W Eksplorator rozwiązań kliknij prawym przyciskiem myszy węzeł projektu (bezpośrednio pod węzłem góry/rozwiązania), a następnie wybierz pozycję Zarządzaj pakietami NuGet...:

    • Po otwarciu karty Menedżer pakietów NuGet w obszarze karty Grupa edytora:

      • Wybierz przycisk Przeglądaj.
      • Wprowadź ciąg "Microsoft.InformationProtection" w polu wyszukiwania.
      • Wybierz pakiet "Microsoft.InformationProtection.File".
      • Kliknij przycisk "Zainstaluj", a następnie kliknij przycisk "OK", gdy zostanie wyświetlone okno dialogowe potwierdzenia podglądu .

      Visual Studio add NuGet package

Implementowanie klasy obserwatora w celu monitorowania obiektów profilu pliku i aparatu

Teraz utwórz podstawową implementację klasy obserwatora profilu plików, rozszerzając klasę zestawu SDK mip::FileProfile::Observer . Obserwator jest tworzone i używane później do monitorowania ładowania obiektu profilu pliku i dodawania obiektu aparatu do profilu.

  1. Dodaj nową klasę do projektu, która generuje pliki header/.h i implementation/.cpp:

    • W Eksplorator rozwiązań ponownie kliknij prawym przyciskiem myszy węzeł projektu, wybierz polecenie Dodaj, a następnie wybierz pozycję Klasa.

    • W oknie dialogowym Dodawanie klasy:

      • W polu Nazwa klasy wprowadź ciąg "profile_observer". Zwróć uwagę, że pola pliku .h i pliku cpp są wypełniane automatycznie na podstawie wprowadzonej nazwy.
      • Po zakończeniu kliknij przycisk OK .

      Visual Studio add class

  2. Po wygenerowaniu plików .h i cpp dla klasy oba pliki są otwierane na kartach Grupy edytorów. Teraz zaktualizuj każdy plik, aby zaimplementować nową klasę obserwatora:

    • Zaktualizuj element "profile_observer.h", wybierając/usuwając wygenerowaną profile_observer klasę. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include). Następnie skopiuj/wklej następujące źródło do pliku po istniejących dyrektywach preprocesora:

      #include <memory>
      #include "mip/file/file_profile.h"
      
      class ProfileObserver final : public mip::FileProfile::Observer {
      public:
           ProfileObserver() { }
           void OnLoadSuccess(const std::shared_ptr<mip::FileProfile>& profile, const std::shared_ptr<void>& context) override;
           void OnLoadFailure(const std::exception_ptr& error, const std::shared_ptr<void>& context) override;
           void OnAddEngineSuccess(const std::shared_ptr<mip::FileEngine>& engine, const std::shared_ptr<void>& context) override;
           void OnAddEngineFailure(const std::exception_ptr& error, const std::shared_ptr<void>& context) override;
      };
      
    • Zaktualizuj plik "profile_observer.cpp", wybierając/usuwając implementację wygenerowanej profile_observer klasy. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include). Następnie skopiuj/wklej następujące źródło do pliku po istniejących dyrektywach preprocesora:

      #include <future>
      
      using std::promise;
      using std::shared_ptr;
      using std::static_pointer_cast;
      using mip::FileEngine;
      using mip::FileProfile;
      
      void ProfileObserver::OnLoadSuccess(const shared_ptr<FileProfile>& profile, const shared_ptr<void>& context) {
           auto promise = static_pointer_cast<std::promise<shared_ptr<FileProfile>>>(context);
           promise->set_value(profile);
      }
      
      void ProfileObserver::OnLoadFailure(const std::exception_ptr& error, const shared_ptr<void>& context) {
           auto promise = static_pointer_cast<std::promise<shared_ptr<FileProfile>>>(context);
           promise->set_exception(error);
      }
      
      void ProfileObserver::OnAddEngineSuccess(const shared_ptr<FileEngine>& engine, const shared_ptr<void>& context) {
           auto promise = static_pointer_cast<std::promise<shared_ptr<FileEngine>>>(context);
           promise->set_value(engine);
      }
      
      void ProfileObserver::OnAddEngineFailure(const std::exception_ptr& error, const shared_ptr<void>& context) {
           auto promise = static_pointer_cast<std::promise<shared_ptr<FileEngine>>>(context);
           promise->set_exception(error);
      }
      
  3. Opcjonalnie użyj klawisza F6 (Kompiluj rozwiązanie), aby uruchomić kompilowanie/łącze testowe rozwiązania, aby upewnić się, że kompilacja została pomyślnie skompilowana przed kontynuowaniem.

Implementowanie delegata uwierzytelniania

Zestaw MIP SDK implementuje uwierzytelnianie przy użyciu rozszerzalności klas, co zapewnia mechanizm udostępniania pracy uwierzytelniania z aplikacją kliencką. Klient musi uzyskać odpowiedni token dostępu OAuth2 i udostępnić zestaw MIP SDK w czasie wykonywania.

Teraz utwórz implementację dla delegata uwierzytelniania, rozszerzając klasę zestawu SDK mip::AuthDelegate i przesłaniając/implementując czystą funkcję wirtualną mip::AuthDelegate::AcquireOAuth2Token() . Delegat uwierzytelniania jest tworzone i używane później przez obiekty Profil pliku i Aparat plików.

  1. Używając tej samej funkcji "Dodaj klasę" programu Visual Studio, której użyliśmy w kroku 1 poprzedniej sekcji, dodaj kolejną klasę do projektu. Tym razem wprowadź ciąg "auth_delegate" w polu Nazwa klasy.

  2. Teraz zaktualizuj każdy plik, aby zaimplementować nową klasę delegata uwierzytelniania:

    • Zaktualizuj wartość "auth_delegate.h", zastępując cały wygenerowany auth_delegate kod klasy następującym źródłem. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include):

      #include <string>
      #include "mip/common_types.h"
      
      class AuthDelegateImpl final : public mip::AuthDelegate {
      public:
           AuthDelegateImpl() = delete;        // Prevents default constructor
      
           AuthDelegateImpl(
             const std::string& appId)         // AppID for registered AAD app
             : mAppId(appId) {};
      
           bool AcquireOAuth2Token(            // Called by MIP SDK to get a token
             const mip::Identity& identity,    // Identity of the account to be authenticated, if known
             const OAuth2Challenge& challenge, // Authority (AAD tenant issuing token), and resource (API being accessed; "aud" claim).
             OAuth2Token& token) override;     // Token handed back to MIP SDK
      
      private:
           std::string mAppId;
           std::string mToken;
           std::string mAuthority;
           std::string mResource;
      };
      
    • Zaktualizuj plik "auth_delegate.cpp", zastępując całą implementację wygenerowanej auth_delegate klasy następującym źródłem. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include).

      Ważne

      Poniższy kod pozyskiwania tokenu nie jest odpowiedni do użytku produkcyjnego. W środowisku produkcyjnym musi to zostać zastąpione przez kod, który dynamicznie uzyskuje token przy użyciu:

      • Identyfikator appId i identyfikator URI odpowiedzi/przekierowania określony w rejestracji aplikacji Microsoft Entra (identyfikator URI odpowiedzi/przekierowania musi być zgodny z rejestracją aplikacji)
      • Adres URL urzędu i zasobu przekazany przez zestaw SDK w argumencie challenge (adres URL zasobu musi być zgodny z interfejsem API/uprawnieniami rejestracji aplikacji)
      • Prawidłowe poświadczenia aplikacji/użytkownika, w których konto jest zgodne z argumentem identity przekazanym przez zestaw SDK. Klienci OAuth2 "natywni" powinni monitować o poświadczenia użytkownika i używać przepływu "kod autoryzacji". Protokół OAuth2 "poufnych klientów" może używać własnych bezpiecznych poświadczeń z przepływem "poświadczeń klienta" (takim jak usługa) lub monitować o poświadczenia użytkownika przy użyciu przepływu "kod autoryzacji" (na przykład aplikacji internetowej).

      Pozyskiwanie tokenów OAuth2 jest złożonym protokołem i zwykle odbywa się przy użyciu biblioteki. TokenAcquireOAuth2Token() jest wywoływany tylko przez zestaw MIP SDK, zgodnie z wymaganiami.

      #include <iostream>
      using std::cout;
      using std::cin;
      using std::string;
      
      bool AuthDelegateImpl::AcquireOAuth2Token(const mip::Identity& identity, const OAuth2Challenge& challenge, OAuth2Token& token) 
      {
           // Acquire a token manually, reuse previous token if same authority/resource. In production, replace with token acquisition code.
           string authority = challenge.GetAuthority();
           string resource = challenge.GetResource();
           if (mToken == "" || (authority != mAuthority || resource != mResource))
           {
               cout << "\nRun the PowerShell script to generate an access token using the following values, then copy/paste it below:\n";
               cout << "Set $authority to: " + authority + "\n";
               cout << "Set $resourceUrl to: " + resource + "\n";
               cout << "Sign in with user account: " + identity.GetEmail() + "\n";
               cout << "Enter access token: ";
               cin >> mToken;
               mAuthority = authority;
               mResource = resource;
               system("pause");
           }
      
           // Pass access token back to MIP SDK
           token.SetAccessToken(mToken);
      
           // True = successful token acquisition; False = failure
           return true;
      }
      
  3. Opcjonalnie użyj klawisza F6 (Kompiluj rozwiązanie), aby uruchomić kompilowanie/łącze testowe rozwiązania, aby upewnić się, że kompilacja została pomyślnie skompilowana przed kontynuowaniem.

Teraz utwórz implementację delegata zgody, rozszerzając klasę zestawu SDK mip::ConsentDelegate i przesłaniając/implementując czystą funkcję wirtualną mip::AuthDelegate::GetUserConsent() . Pełnomocnik zgody jest tworzone i używane później przez obiekty Profil pliku i Aparat plików.

  1. Korzystając z tej samej funkcji "Dodaj klasę" programu Visual Studio, której użyliśmy wcześniej, dodaj kolejną klasę do projektu. Tym razem wprowadź ciąg "consent_delegate" w polu Nazwa klasy.

  2. Teraz zaktualizuj każdy plik, aby zaimplementować nową klasę delegata zgody:

    • Zaktualizuj wartość "consent_delegate.h", zastępując cały wygenerowany consent_delegate kod klasy następującym źródłem. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include):

      #include "mip/common_types.h"
      #include <string>
      
      class ConsentDelegateImpl final : public mip::ConsentDelegate {
      public:
           ConsentDelegateImpl() = default;
           virtual mip::Consent GetUserConsent(const std::string& url) override;
      };
      
    • Zaktualizuj plik "consent_delegate.cpp", zastępując całą implementację wygenerowanej consent_delegate klasy następującym źródłem. Nie usuwaj dyrektyw preprocesora wygenerowanych w poprzednim kroku (#pragma, #include).

      #include <iostream>
      using mip::Consent;
      using std::string;
      
      Consent ConsentDelegateImpl::GetUserConsent(const string& url) 
      {
           // Accept the consent to connect to the url
           std::cout << "SDK will connect to: " << url << std::endl;
           return Consent::AcceptAlways;
      }
      
  3. Opcjonalnie użyj klawisza F6 (Kompiluj rozwiązanie), aby uruchomić kompilowanie/łącze testowe rozwiązania, aby upewnić się, że kompilacja została pomyślnie skompilowana przed kontynuowaniem.

Konstruowanie profilu i aparatu plików

Jak wspomniano, obiekty profilów i aparatu są wymagane dla klientów zestawu SDK przy użyciu interfejsów API MIP. Ukończ część kodowania tego przewodnika Szybki start, dodając kod w celu utworzenia wystąpienia obiektów profilu i aparatu:

  1. W Eksplorator rozwiązań otwórz plik cpp w projekcie zawierający implementację main() metody . Domyślnie ma taką samą nazwę jak projekt zawierający go, który został określony podczas tworzenia projektu.

  2. Usuń wygenerowaną implementację elementu main(). Nie usuwaj dyrektyw preprocesora generowanych przez program Visual Studio podczas tworzenia projektu (#pragma, #include). Dołącz następujący kod po wszelkich dyrektywach preprocesora:

#include "mip/mip_context.h"  
#include "auth_delegate.h"
#include "consent_delegate.h"
#include "profile_observer.h"

using std::promise;
using std::future;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::cout;
using mip::ApplicationInfo;
using mip::FileProfile;
using mip::FileEngine;

int main()
{
  // Construct/initialize objects required by the application's profile object
  // ApplicationInfo object (App ID, name, version)
  ApplicationInfo appInfo{"<application-id>",      
                          "<application-name>",
                          "<application-version>"};

  // Create MipConfiguration object.
  std::shared_ptr<mip::MipConfiguration> mipConfiguration = std::make_shared<mip::MipConfiguration>(appInfo,    
				                                                                                               "mip_data", 
                                                                                      			         mip::LogLevel::Trace, 
                                                                                                     false);


  std::shared_ptr<mip::MipContext> mMipContext = mip::MipContext::Create(mipConfiguration);

  auto profileObserver = make_shared<ProfileObserver>();                     // Observer object
  auto authDelegateImpl = make_shared<AuthDelegateImpl>("<application-id>"); // Authentication delegate object (App ID)                 
  auto consentDelegateImpl = make_shared<ConsentDelegateImpl>();             // Consent delegate object

  // Construct/initialize profile object
  FileProfile::Settings profileSettings(
                                mMipContext,
                                mip::CacheStorageType::OnDisk,
                                consentDelegateImpl,
                                profileObserver);

  // Set up promise/future connection for async profile operations; load profile asynchronously
  auto profilePromise = make_shared<promise<shared_ptr<FileProfile>>>();
  auto profileFuture = profilePromise->get_future();

  try
	  { 
		  mip::FileProfile::LoadAsync(profileSettings, profilePromise);
  }
	  catch (const std::exception& e)
	  {
		  cout << "An exception occurred... are the Settings and ApplicationInfo objects populated correctly?\n\n" << e.what() << "'\n";
			
		  system("pause");
		  return 1;
	  }
	  auto profile = profileFuture.get();

  // Construct/initialize engine object
  FileEngine::Settings engineSettings(
                                  mip::Identity("<engine-account>"), // Engine identity (account used for authentication)
                                  authDelegateImpl,		       // Token acquisition implementation
				    "<engine-state>",                  // User-defined engine state
                                  "en-US");                          // Locale (default = en-US)
                                  
  // Set the engineId for caching. 
  engineSettings.SetEngineId("<engine-account>");
  // Set up promise/future connection for async engine operations; add engine to profile asynchronously
  auto enginePromise = make_shared<promise<shared_ptr<FileEngine>>>();
  auto engineFuture = enginePromise->get_future();
  profile->AddEngineAsync(engineSettings, enginePromise);
  std::shared_ptr<FileEngine> engine; 
  try
  {
    engine = engineFuture.get();
  }
  catch (const std::exception& e)
  {
    cout << "An exception occurred... is the access token incorrect/expired?\n\n" << e.what() << "'\n";
     
    system("pause");
    return 1;
  }

  // Application shutdown. Null out profile and engine, call ReleaseAllResources();
  // Application may crash at shutdown if resources aren't properly released.
  // handler = nullptr; // This will be used in later quick starts.
  engine = nullptr;
  profile = nullptr;   
  mMipContext->ShutDown();
  mMipContext = nullptr;

  return 0;
  }
  1. Zastąp wszystkie wartości symboli zastępczych w kodzie źródłowym, w którym właśnie wklejono, używając stałych ciągów:

    Symbol zastępczy Wartość Przykład
    <identyfikator aplikacji> Identyfikator aplikacji Entra firmy Microsoft (GUID) przypisany do aplikacji zarejestrowanej w kroku 2 artykułu "Konfiguracja i konfiguracja zestawu MIP SDK". Zastąp 2 wystąpienia. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <nazwa aplikacji> Przyjazna nazwa aplikacji zdefiniowana przez użytkownika. Musi zawierać prawidłowe znaki ASCII (z wyłączeniem znaku ";") i najlepiej odpowiada nazwie aplikacji użytej w rejestracji firmy Microsoft Entra. "AppInitialization"
    <wersja aplikacji> Informacje o wersji zdefiniowanej przez użytkownika dla aplikacji. Musi zawierać prawidłowe znaki ASCII (z wyłączeniem znaku ";"). "1.1.0.0"
    <konto aparatu> Konto używane do obsługi tożsamości aparatu. Podczas uwierzytelniania przy użyciu konta użytkownika podczas pozyskiwania tokenu musi być zgodna z tą wartością. "user1@tenant.onmicrosoft.com"
    <stan silnika> Stan zdefiniowany przez użytkownika do skojarzenia z aparatem. "My App State"
  2. Teraz wykonaj ostateczną kompilację aplikacji i rozwiąż wszelkie błędy. Kod powinien zostać skompilować pomyślnie, ale nie zostanie jeszcze uruchomiony poprawnie, dopóki nie ukończysz następnego przewodnika Szybki start. Jeśli uruchomisz aplikację, zobaczysz dane wyjściowe podobne do poniższych. Nie będziesz mieć tokenu dostępu do udostępnienia, dopóki nie ukończysz następnego przewodnika Szybki start.

Następne kroki

Teraz, gdy kod inicjowania został ukończony, możesz przystąpić do następnego przewodnika Szybki start, w którym zaczniesz korzystać z zestawów SDK plików MIP.