Szybki start: inicjowanie aplikacji klienckiej (C++)

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

Uwaga

Kroki opisane w tym przewodniku Szybki start są wymagane dla każdej aplikacji klienckiej, która korzysta z pliku MIP, zasad lub zestawów SDK ochrony. Ten szybki start pokazuje użycie zestawów SDK plików, jednak ten sam wzorzec obowiązuje dla klientów korzystających z zestawów SDK zasad i ochrony. Wykonaj pozostałe zadania Szybki start po raz kolejny, ponieważ każda z nich jest kompilowana na poprzednim, przy tym pierwszym.

Wymagania wstępne

Jeśli jeszcze tego nie zrobić, pamiętaj, aby:

  • Wykonaj czynności opisane w te Microsoft Information Protection (MIP) SDK konfiguracji. Ten przewodnik Szybki start "Inicjowanie aplikacji klienckich" korzysta z odpowiedniej konfiguracji i konfiguracji zestawu SDK.
  • Opcjonalnie:
    • Przejrzyj obiekty profilów i aparatów. Obiekty profilu i aparatu to uniwersalne koncepcje wymagane przez klientów, którzy korzystają z zestawów SDK plików/zasad/ochrony miP.
    • Zapoznaj się z pojęciami uwierzytelniania, aby dowiedzieć się, jak uwierzytelnianie i zgoda są zaimplementowane przez zestaw SDK i aplikację kliencną.
    • Przejrzyj koncepcje konceptuu, aby dowiedzieć się więcej na temat obserwatorów i sposobu ich wdrożenia. Zestaw SDK MIP używa wzorca wzorców asynchronicznych powiadomień o zdarzeniach.

Tworzenie Visual Studio i projektu

Najpierw tworzymy i konfigurujemy początkowe Visual Studio rozwiązania i projektu, na podstawie którego są konstruowane inne szybkie starty.

  1. Otwórz Visual Studio 2017, wybierz menu Plik,Nowy, Project. W oknie Project dialogowym Nowe:

    • W okienku po lewej stronie w obszarze Zainstalowane, Inne językiwybierz Visual C++.

    • W środkowym okienku wybierz pozycję Windows Konsoli

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

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

      Visual Studio tworzenia rozwiązań

  2. Dodaj pakiet Nuget do zestawu SDK pliku MIP do projektu:

    • W Eksploratorze rozwiązańkliknij prawym przyciskiem myszy węzeł projektu (bezpośrednio poniżej węzła górnego/węzła rozwiązania) i wybierz pozycję Zarządzaj NuGet pakietami...:

    • Gdy karta NuGet Menedżer pakietów zostanie otwarta w obszarze kart Grupy edytorów:

      • Wybierz pozycję Przeglądaj.
      • W polu wyszukiwania wprowadź "Microsoft.InformationProtection".
      • Wybierz pakiet "Microsoft.InformationProtection.File".
      • Kliknij przycisk "Zainstaluj", a następnie kliknij przycisk "OK", gdy zostanie wyświetlone okno dialogowe potwierdzenia zmian w podglądzie.

      Visual Studio dodaj NuGet pakietu

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

Teraz należy utworzyć podstawową implementację klasy profilu pliku przez rozszerzenie klasy zestawu mip::FileProfile::Observer SDK. Obserwator jest wytężany i używany później do monitorowania ładowania obiektu Profilu pliku oraz dodawania obiektu aparatu do profilu.

  1. Dodaj do projektu nową klasę, która wygeneruje dla Ciebie zarówno pliki nagłówka/.h, jak i implementacji/.cpp:

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

    • W oknie dialogowym Dodawanie zajęć:

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

      Visual Studio dodawania zajęć

  2. Po wygenerowaniu plików h i cpp dla zajęć oba pliki są otwierane na kartach Grupy Redaktora. Teraz zaktualizuj każdy plik, aby wdrożyć swoją nową klasę obserwatorów:

    • Zaktualizuj "profile_observer.h", zaznaczając/usuwając wygenerowaną profile_observer klasę. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #pragma, #include). Następnie skopiuj/wklej do pliku następujące źródło po jakiejkolwiek istniejącej zaraz przedprocesorowi.

      #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 "profile_observer.cpp", wybierając/usuwając wygenerowaną profile_observer implementację klasy. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #pragma, #include). Następnie skopiuj/wklej do pliku następujące źródło po jakiejkolwiek istniejącej zaraz przedprocesorowi.

      #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(kompilacjarozwiązania), aby uruchomić testowe zestawienie/link do rozwiązania, aby upewnić się, że będzie ono pomyślnie kompilowane przed kontynuowaniem.

Implementowanie pełnomocnika uwierzytelniania

Zestaw SDK protokołu MIP implementuje uwierzytelnianie za pomocą rozszerzalności klasy, który udostępnia mechanizm udostępniania uwierzytelniania podczas pracy z aplikacją kliencową. Klient musi uzyskać odpowiedni token dostępu OAuth2 i podać zestaw SDK MIP w czasie wykonywania.

Teraz utwórz implementację pełnomocnika uwierzytelniania, rozszerzając klasę zestawu SDK mip::AuthDelegate i zastępując/implementując funkcję mip::AuthDelegate::AcquireOAuth2Token() wyłącznie wirtualną. Pełnomocnik uwierzytelniania jest wystąpienia i używany później przez obiekty Profil pliku i Aparat plików.

  1. Używając tej samej Visual Studio "Dodaj zajęcia" użytej w kroku nr 1 poprzedniej sekcji, dodaj kolejne zajęcia do projektu. Tym razem wprowadź "auth_delegate" w polu Nazwa zajęć.

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

    • Zaktualizuj plik "auth_delegate.h", zastępując cały wygenerowany kod auth_delegate klasy następującym źródłem. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #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 wszystkie wygenerowane auth_delegate implementacje klasy następującym źródłem. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #pragma, #include).

      Ważne

      Poniższy kod nabycia tokenu nie nadaje się do użytku produkcyjnego. W środowisku produkcyjnym musi to zostać zastąpione kodem, który dynamicznie otrzymuje token, używając:

      • The appId and reply/redirect URI specified in your Azure AD app registration (reply/redirect URI must match match your app registration)
      • Urząd i adres URL zasobu przekazany przez zestaw SDK w tym argumentie (adres URL zasobu musi być zgodne z interfejsem challenge API/uprawnieniami rejestracji aplikacji) challenge
      • Prawidłowe poświadczenia aplikacji/użytkownika, dla których konto jest odpowiednie dla identity argumentu przekazywanego przez zestaw SDK. Klienci "natywny" OAuth2 powinni monitować o poświadczenia użytkownika i używać przepływu "autoryzacji". "Klienci poufni" OAuth2 mogą używać własnych bezpiecznych poświadczeń przy użyciu przepływu "poświadczeń klienta" (na przykład usługi) lub monitować o poświadczenia użytkowników przy użyciu przepływu "kod autoryzacji" (na przykład aplikacji sieci Web).

      Pozyskiwanie tokenu OAuth2 jest złożonym protokołem i zwykle odbywa się przy użyciu biblioteki. TokenAcquireOAuth2Token() jest wywoływany tylko przez zestaw SDK MIP, 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(kompilacjarozwiązania), aby uruchomić testowe zestawienie/link do rozwiązania, aby upewnić się, że będzie ono pomyślnie kompilowane przed kontynuowaniem.

Teraz utwórz implementację pełnomocnika zgody, rozszerzając klasę zestawu SDK mip::ConsentDelegate i zastępując/implementując funkcję mip::AuthDelegate::GetUserConsent() wyłącznie wirtualną. Pełnomocnik zgody jest wystąpienia i używany później przez obiekty Profil pliku i Aparat plików.

  1. Używając tej samej Visual Studio "Dodaj zajęcia" użytej wcześniej, dodaj kolejne zajęcia do projektu. Tym razem wprowadź "consent_delegate" w polu Nazwa zajęć.

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

    • Zaktualizuj "consent_delegate.h", zastępując cały wygenerowany kod consent_delegate klasy następującym źródłem. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #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 wszystkie wygenerowane consent_delegate implementacje klasy następującym źródłem. Nie usuwaj użytkowników przedprocesowych wygenerowanych w poprzednim kroku (na przykład #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(kompilacjarozwiązania), aby uruchomić testowe zestawienie/link do rozwiązania, aby upewnić się, że będzie ono pomyślnie kompilowane przed kontynuowaniem.

Konstruowanie profilu pliku i aparatu

Jak wspomniano, obiekty profilu i aparatu są wymagane dla klientów zestawu SDK korzystających z interfejsów API miP. Ukończ kodowanie tej funkcji Szybki start, dodając kod w celu wystąpienia obiektów profilu i aparatu:

  1. W Eksploratorze rozwiązańotwórz plik cpp w projekcie, który zawiera implementację metody. Domyślna nazwa jest taka sama jak nazwa projektu zawierającego projekt, która jest określona podczas tworzenia projektu.

  2. Usuń wygenerowaną implementację main() programu . Nie usuwaj preprocesorów wygenerowanych przez Visual Studio podczas tworzenia projektu (#pragma, #include). Dołącz następujący kod po wszystkich przedprocesowych danych źródłowych:

#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>(mAppInfo,    
				                                                                                               "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,
                                authDelegateImpl,
                                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)
                                  "<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;   
  mipContext.Shutdown();
  mipContext = nullptr;

  return 0;
  }
  1. Zamień wszystkie wartości zastępcze w właśnie wklejonym kodzie źródłowym, używając stałych ciągów:

    Symbol zastępczy Wartość Przykład
    <application-id> Identyfikator aplikacji usługi Azure AD (GUID) przypisany do aplikacji zarejestrowanej w kroku 2 artykułu "Konfiguracja i konfiguracja zestawu SDK MIP". Zamień 2 wystąpienia. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <nazwa aplikacji> Zdefiniowana przez użytkownika przyjazna nazwa aplikacji. Musi zawierać prawidłowe znaki ASCII (z wyjątkiem znaków ';') i najlepiej pasuje do nazwy aplikacji użytej podczas rejestracji w usłudze Azure AD. "AppInitialization"
    <application-version> Informacje o wersji zdefiniowanej przez użytkownika dla aplikacji. Musi zawierać prawidłowe znaki ASCII (z wyjątkiem znaków ';'). "1.1.0.0"
    <engine-account> Konto używane na celu tożsamości aparatu. Uwierzytelnianie przy użyciu konta użytkownika podczas pozyskiwania tokenu musi być zgodne z tą wartością. "user1@tenant.onmicrosoft.com"
    <stan-aparat> Stan zdefiniowany przez użytkownika, który ma zostać skojarzony z aparatem. "My App State"
  2. Teraz wykonaj ostateczną kompilację aplikacji i rozwiąż wszelkie błędy. Kod powinien zostać pomyślnie skompilowany, ale nie będzie działał poprawnie do momentu ukończenia następnego przewodnika Szybki start. Po uruchomieniu aplikacji zobaczysz dane wyjściowe podobne do poniższych. Nie będziesz mieć tokenu dostępu do podania, dopóki nie ukończysz następnego przewodnika Szybki start.

Następne kroki

Teraz, gdy kod inicjowania został ukończony, możesz rozpocząć kolejny szybki start, w którym będą dostępne zestawy SDK plików MIP.