Schnellstart: Initialisieren von Clientanwendungen (C++)

In diesem Schnellstart erfahren Sie, wie Sie das Muster für die Clientinitialisierung implementieren, das zur Laufzeit vom MIP SDK für C++ ausgeführt wird.

Notiz

Die in diesem Schnellstart beschriebenen Schritte müssen für sämtliche Clientanwendungen ausgeführt werden, die MIP File SDKs, Policy SDKs oder Protection SDKs verwenden. Zwar wird in diesem Schnellstart die Verwendung von File SDKs gezeigt, das gleiche Muster ist jedoch auch auf Clients anwendbar, die das Policy SDK oder das Protection SDK verwenden. Beginnen Sie mit diesem Schnellstart, und schließen Sie die übrigen der Reihe nach ab, da sie aufeinander aufbauen.

Voraussetzungen

Falls noch nicht geschehen, sorgen Sie für Folgendes:

  • Führen Sie die Schritte unter Microsoft Information Protection (MIP) SDK: Setup und Konfiguration aus. Dieser Schnellstart „Initialisieren von Clientanwendungen“ basiert auf der ordnungsgemäßen Einrichtung und Konfiguration des SDK.
  • Optional:
    • Informieren Sie sich über Profil- und Engine-Objekte. Bei Profil- und Engine-Objekten handelt es sich um universelle Konzepte, die von Clients benötigt werden, die das File SDK, das Policy SDK oder das Protection SDK von MIP verwenden.
    • Informieren Sie sich über Authentifizierungskonzepte, um zu erfahren, wie die Authentifizierung und die Einwilligung vom SDK und der Clientanwendung implementiert werden.
    • Informieren Sie sich über Observer-Konzepte, um mehr über Observer und ihre Implementierung zu erfahren. Das MIP SDK verwendet das Observer-Muster, um asynchrone Ereignisbenachrichtigungen zu implementieren.

Erstellen einer Visual Studio-Projektmappe und eines -Projekts

Zunächst erstellen und konfigurieren Sie die erste Projektmappe und das erste Projekt in Visual Studio. Sie bilden die Grundlage für die anderen Schnellstarts.

  1. Öffnen Sie Visual Studio 2017, und wählen Sie das Menü Datei, anschließend Neu und dann Projekt aus. Geben Sie im Dialogfeld Neues Projekt Folgendes ein:

    • Wählen Sie im linken Bereich unter Installiert, Andere Sprachen die Option Visual C++ aus.

    • Wählen Sie im mittleren Bereich Windows-Konsolenanwendung aus

    • Aktualisieren Sie im unteren Bereich Name, Speicherort und den darin enthaltenen Projektmappennamen des Projekts.

    • Wenn Sie fertig sind, klicken Sie rechts unten auf die Schaltfläche OK.

      Visual Studio solution creation

  2. Fügen Sie Ihrem Projekt das NuGet-Paket für das MIP File SDK hinzu:

    • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektknoten direkt unter dem obersten Knoten bzw. dem Projektmappenknoten, und wählen Sie NuGet-Pakete verwalten… aus:

    • Gehen Sie wie folgt vor, wenn im Bereich „Editor-Gruppe“ die Registerkarte NuGet-Paket-Manager geöffnet wird:

      • Wählen Sie Durchsuchen aus.
      • Geben Sie „Microsoft.InformationProtection“ in das Suchfeld ein.
      • Wählen Sie das Paket „Microsoft.InformationProtection.File“ aus.
      • Klicken Sie auf „Installieren“ und anschließend auf „OK“, wenn das Bestätigungsdialogfeld Vorschau der Änderungen anzeigen angezeigt wird.

      Visual Studio add NuGet package

Implementieren einer Observer-Klasse zum Überwachen der File-Profil- und File-Engine-Objekte

Erstellen Sie nun eine grundlegende Implementierung für eine Observer-Klasse des File-Profils, indem Sie die mip::FileProfile::Observer-Klasse des SDK erweitern. Der Observer wird später instanziiert und verwendet, um den Ladevorgang des File-Profilobjekts zu überwachen und dem Profil das Engine-Objekt hinzuzufügen.

  1. Fügen Sie Ihrem Projekt eine neue Klasse hinzu, durch die die Dateien „header/.h“ und „implementation/.cpp“ für Sie generiert werden:

    • Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste erneut auf den Projektknoten, und wählen Sie Hinzufügen und dann Klasse aus.

    • Gehen Sie im Dialogfeld Klasse hinzufügen folgendermaßen vor:

      • Geben Sie im Feld Klassenname „profile_observer“ ein. Die Felder H-Datei und CPP-Datei werden anhand des eingegebenen Namens automatisch ausgefüllt.
      • Wenn Sie fertig sind, klicken Sie auf die Schaltfläche OK.

      Visual Studio add class

  2. Nach dem Generieren der H- und der CPP-Dateien für die Klasse werden beide Dateien auf Registerkarten in „Editor-Gruppe“ geöffnet. Aktualisieren Sie jetzt jede Datei, um Ihre neue Observer-Klasse zu implementieren:

    • Aktualisieren Sie „profile_observer.h“, indem Sie die generierte profile_observer-Klasse auswählen/löschen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#pragma, #include). Kopieren Sie dann die folgende Quelle, und fügen Sie sie in der Datei nach den vorhandenen Präprozessoranweisungen ein:

      #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;
      };
      
    • Aktualisieren Sie „profile_observer.cpp“, indem Sie die Implementierung der generierten profile_observer-Klasse auswählen/löschen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#pragma, #include). Kopieren Sie dann die folgende Quelle, und fügen Sie sie in der Datei nach den vorhandenen Präprozessoranweisungen ein:

      #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. Verwenden Sie optional F6 (Projektmappe erstellen), um eine Testkompilierung/-verknüpfung Ihrer Projektmappe auszuführen und vor dem Fortfahren sicherzustellen, dass sie erfolgreich erstellt wird.

Implementieren eines Authentifizierungsdelegaten

Das MIP SDK implementiert die Authentifizierung mithilfe der Klassenerweiterbarkeit, die einen Mechanismus zur Freigabe der Authentifizierung für die Clientanwendung bietet. Der Client muss ein geeignetes OAuth2-Zugriffstoken abrufen und dem MIP SDK zur Laufzeit bereitstellen.

Erstellen Sie nun eine Implementierung für einen Authentifizierungsdelegaten, indem Sie die mip::AuthDelegate-Klasse des SDK erweitern und die rein virtuelle mip::AuthDelegate::AcquireOAuth2Token()-Funktion überschreiben/implementieren. Der Authentifizierungsdelegat wird später von den File-Profil- und File-Engine-Objekten instanziiert und verwendet.

  1. Fügen Sie mit der gleichen Visual Studio-Funktion „Klasse hinzufügen“, die Sie im vorherigen Abschnitt in Schritt 1 verwendet haben, Ihrem Projekt eine weitere Klasse hinzu. Geben Sie dieses Mal „auth_delegate“ in das Feld Klassenname ein.

  2. Aktualisieren Sie nun jede Datei, um Ihre neue Authentifizierungsdelegatklasse zu implementieren:

    • Aktualisieren Sie „auth_delegate.h“, indem Sie den gesamten generierten Code der auth_delegate-Klasse durch die folgende Quelle ersetzen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#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;
      };
      
    • Aktualisieren Sie „auth_delegate.cpp“, indem Sie die gesamte Implementierung der auth_delegate-Klasse durch die folgende Quelle ersetzen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#pragma, #include).

      Wichtig

      Der folgende Code für den Tokenabruf eignet sich nicht für die Produktion. In der Produktion muss er durch Code ersetzt werden, mit dem ein Token dynamisch abgerufen wird, und zwar mithilfe von:

      • Der App-ID und dem Antwort- bzw. Umleitungs-URI, die in der Registrierung Ihrer Azure AD-App angegeben sind. Der Antwort- bzw. Umleitungs-URI muss Ihrer App-Registrierung entsprechen.
      • Der Autoritäts- und Ressourcen-URL, die vom SDK im challenge-Argument übergeben werden. Die Ressourcen-URL muss der API bzw. den Berechtigungen Ihrer App-Registrierung entsprechen.
      • Gültigen App- bzw. Benutzeranmeldeinformationen, bei denen das Konto dem vom SDK übergebenen identity-Argument entspricht. „Native“ OAuth2-Clients sollten zur Eingabe von Benutzeranmeldeinformationen auffordern und den Flow „Autorisierungscode“ verwenden. „Vertrauliche“ OAuth2-Clients können ihre eigenen sicheren Anmeldeinformationen mit dem Flow „Clientanmeldeinformationen“ (z. B. ein Dienst) verwenden oder über den Flow „Autorisierungscode“ (z. B. eine Web-App) zur Eingabe von Benutzeranmeldeinformationen auffordern.

      Beim OAuth2-Tokenabruf handelt es sich um ein komplexes Protokoll. Er erfolgt in der Regel mithilfe einer Bibliothek. TokenAcquireOAuth2Token() wird bei Bedarf nur vom MIP SDK abgerufen.

      #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. Verwenden Sie optional F6 (Projektmappe erstellen), um eine Testkompilierung/-verknüpfung Ihrer Projektmappe auszuführen und vor dem Fortfahren sicherzustellen, dass sie erfolgreich erstellt wird.

Erstellen Sie nun eine Implementierung für einen Einwilligungsdelegaten, indem Sie die mip::ConsentDelegate-Klasse des SDK erweitern und die rein virtuelle mip::AuthDelegate::GetUserConsent()-Funktion überschreiben/implementieren. Der Einwilligungsdelegat wird später von den File-Profil- und File-Engine-Objekten instanziiert und verwendet.

  1. Fügen Sie mit der gleichen Visual Studio-Funktion „Klasse hinzufügen“, die Sie vorher verwendet haben, Ihrem Projekt eine weitere Klasse hinzu. Geben Sie dieses Mal „content_delegate“ in das Feld Klassenname ein.

  2. Aktualisieren Sie jetzt jede Datei, um Ihre neue Einwilligungsdelegatklasse zu implementieren:

    • Aktualisieren Sie „consent_delegate.h“, indem Sie den gesamten Code der consent_delegate-Klasse durch die folgende Quelle ersetzen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#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;
      };
      
    • Aktualisieren Sie „consent_delegate.cpp“, indem Sie die gesamte Implementierung der generierten consent_delegate-Klasse durch die folgende Quelle ersetzen. Entfernen Sie nicht die im vorherigen Schritt generierten Präprozessoranweisungen (#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. Verwenden Sie optional F6 (Projektmappe erstellen), um eine Testkompilierung/-verknüpfung Ihrer Projektmappe auszuführen und vor dem Fortfahren sicherzustellen, dass sie erfolgreich erstellt wird.

Erstellen eines File-Profils und einer File-Engine

Wie bereits erwähnt sind für SDK-Clients, die MIP-APIs verwenden, Profil- und Engine-Objekte erforderlich. Vervollständigen Sie den Codierungsabschnitt in diesem Schnellstart, indem Sie Code hinzufügen, um die Profil- und Engine-Objekte zu instanziieren:

  1. Öffnen Sie im Projektmappen-Explorer die CPP-Datei in Ihrem Projekt, die die Implementierung der main()-Methode enthält. Standardmäßig weist sie denselben Namen wie das Projekt auf, in dem sie enthalten ist. Diesen Namen haben Sie bei der Projekterstellung angegeben.

  2. Entfernen Sie die generierte Implementierung von main(). Entfernen Sie keine Präprozessoranweisungen, die während der Projekterstellung von Visual Studio generiert wurden (#pragma, #include). Fügen Sie folgenden Code hinter den Präprozessoranweisungen an:

#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. Ersetzen Sie alle Platzhalterwerte in dem Quellcode, den Sie gerade eingefügt haben, durch Zeichenfolgenkonstanten:

    Platzhalter Wert Beispiel
    <application-id> Die ID der Azure AD-Anwendung (GUID) wird der Anwendung zugewiesen, die in Schritt 2 des Artikels MIP SDK: Setup und Konfiguration registriert wurde. Ersetzen Sie 2 Instanzen. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <application-name> Ein benutzerdefinierter Anzeigename für Ihre Anwendung. Dieser muss aus gültigen ASCII-Zeichen (außer „;“) bestehen und im Idealfall mit dem Anwendungsnamen übereinstimmen, den Sie während der Azure AD-Registrierung verwendet haben. "AppInitialization"
    <application-version> Die benutzerdefinierten Versionsinformationen für Ihre Anwendung. Sie muss aus gültigen ASCII-Zeichen (außer „;“) bestehen. "1.1.0.0"
    <engine-account> Das Konto, das für die Identität der Engine verwendet wird. Wenn Sie sich während des Tokenabrufs mit einem Benutzerkonto authentifizieren, muss es diesem Wert entsprechen. "user1@tenant.onmicrosoft.com"
    <engine-state> Der benutzerdefinierte Status, der der Engine zugeordnet werden soll. "My App State"
  2. Stellen Sie nun die Anwendung endgültig fertig, und beheben Sie etwaige Fehler. Ihr Code sollte erfolgreich erstellt werden. Er wird jedoch erst ordnungsgemäß ausgeführt, wenn Sie den nächsten Schnellstart abgeschlossen haben. Beim Ausführen der Anwendung wird Ihnen eine ähnliche Ausgabe wie die folgende angezeigt. Sie können erst dann ein Zugriffstoken bereitstellen, wenn Sie den nächsten Schnellstart abgeschlossen haben.

Nächste Schritte

Da Ihr Initialisierungscode nun vollständig ist, können Sie mit dem nächsten Schnellstart fortfahren. Darin erfahren Sie mehr über die MIP File SDKs.