Schnellstart: Clientanwendungsinitialisierung (C++)

In dieser Schnellstartanleitung erfahren Sie, wie Sie das Clientinitialisierungsmuster implementieren, das das MIP C++-SDK zur Laufzeit verwendet.

Hinweis

Jede Clientanwendung, die die MIP-Datei, Richtlinie oder Schutz-SDKs verwendet, erfordert die in dieser Schnellstartanleitung beschriebenen Schritte. Obwohl diese Schnellstartanleitung die Verwendung der Datei-SDKs veranschaulicht, gilt dieses Muster für Clients, die die Richtlinien- und Schutz-SDKs verwenden. Schließen Sie die restlichen Schnellstarts fortlaufend ab, da jeder auf dem vorherigen aufbaut, wobei dies der erste ist.

Voraussetzungen

Falls noch nicht geschehen, stellen Sie sicher, dass Sie:

  • Führen Sie die Schritte im Microsoft Information Protection (MIP)-SDK-Setup und -Konfiguration aus. Diese Schnellstartanleitung "Clientanwendungsinitialisierung" basiert auf der richtigen SDK-Einrichtung und -Konfiguration.
  • Optional:
    • Überprüfen Sie Profil- und Modulobjekte. Die Profil- und Modulobjekte sind universelle Konzepte, die von Clients benötigt werden, die die MIP File/Policy/Protection SDKs verwenden.
    • Überprüfen Sie die Authentifizierungskonzepte , um zu erfahren, wie das SDK und die Clientanwendung Authentifizierung und Zustimmung implementieren.
    • Sehen Sie sich die Beobachterkonzepte an, um mehr über Beobachter zu erfahren und wie sie implementiert werden. Das MIP SDK verwendet das Beobachtermuster, um asynchrone Ereignisbenachrichtigungen zu implementieren.

Visual Studio-Lösung und Projekt erstellen

Erstellen und konfigurieren Sie zunächst die erste Visual Studio Lösung und das Projekt, auf der die anderen Schnellstarts erstellt werden.

  1. Öffnen Sie Visual Studio 2022 oder höher, wählen Sie das Menü "Datei ", "Neu", "Projekt" aus. Im Dialogfeld "Neues Projekt ":

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

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

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

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

      Visual Studio Lösungserstellung.

  2. Fügen Sie dem 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 oberen/Projektmappenknoten), und wählen Sie "NuGet-Pakete verwalten"...:

    • Wenn die Registerkarte "NuGet-Paket-Manager " im Bereich "Editorgruppe" geöffnet wird:

      • Tippen Sie auf Browse (Durchsuchen).
      • Geben Sie "Microsoft.InformationProtection" in das Suchfeld ein.
      • Wählen Sie das Paket "Microsoft.InformationProtection.File" aus.
      • Klicken Sie auf "Installieren" und dann auf "OK", wenn der Bestätigungsdialog "Änderungen anzeigen" angezeigt wird.

      Visual Studio NuGet-Paket hinzufügen.

Implementieren Sie eine Beobachterklasse, um die Datei-Profil- und Engine-Objekte zu überwachen.

Erstellen Sie nun eine grundlegende Implementierung für eine Dateiprofilbeobachterklasse, indem Sie die SDK-Klasse mip::FileProfile::Observer erweitern. Sie instanziieren und verwenden den Observer später, 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, die sowohl die Header/.h- als auch die Implementierungs-/.cpp dateien für Sie generiert:

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

    • Im Dialogfeld "Klasse hinzufügen ":

      • Geben Sie im Feld "Klassenname " "profile_observer" ein. Beachten Sie, dass sowohl die H-Datei als auch .cpp Dateifelder basierend auf dem eingegebenen Namen automatisch ausgefüllt werden.
      • Klicken Sie abschließend auf die Schaltfläche "OK ".

      Visual Studio Klasse hinzufügen.

  2. Nachdem Sie die .h- und .cpp-Dateien für die Klasse generiert haben, öffnet Visual Studio beide Dateien in Registerkarten der Editorgruppe. Aktualisieren Sie nun jede Datei, um Ihre neue Beobachterklasse zu implementieren:

    • Aktualisieren Sie "profile_observer.h", indem Sie die generierte profile_observer Klasse auswählen/löschen. Entfernen Sie die vom vorherigen Schritt generierten Präprozessordirektiven nicht (#pragma, #include). Kopieren/fügen Sie dann die folgende Quelle nach vorhandenen Präprozessordirektiven in die Datei 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 generierte profile_observer Klassenimplementierung auswählen/löschen. Entfernen Sie die vom vorherigen Schritt generierten Präprozessordirektiven nicht (#pragma, #include). Kopieren/fügen Sie dann die folgende Quelle nach vorhandenen Präprozessordirektiven in die Datei 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 (Buildlösung), um eine Testkompilierung/Verknüpfung Ihrer Lösung auszuführen, um sicherzustellen, dass sie erfolgreich erstellt wird, bevor Sie fortfahren.

Implementieren eines Authentifizierungsdelegats

Das MIP-SDK realisiert die Authentifizierung mithilfe der Erweiterbarkeit von Klassen, wodurch ein Mechanismus bereitgestellt wird, um Authentifizierungsaufgaben mit der Clientanwendung zu teilen. Der Client muss ein geeignetes OAuth2-Zugriffstoken erwerben und es zur Laufzeit dem MIP SDK bereitstellen.

Erstellen Sie nun eine Implementierung für einen Authentifizierungsdelegat, indem Sie die Klasse des mip::AuthDelegate SDK erweitern und die mip::AuthDelegate::AcquireOAuth2Token() reine virtuelle Funktion außer Kraft setzen oder implementieren. Die Objekte „Dateiprofil“ und „Datei-Engine“ instanziieren den Authentifizierungsdelegaten und verwenden ihn später.

  1. Fügen Sie mit dem gleichen Visual Studio-Feature "Klasse hinzufügen", das wir in Schritt #1 des vorherigen Abschnitts verwendet haben, eine weitere Klasse zu Ihrem Projekt 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 auth_delegate Klassencode durch die folgende Quelle ersetzen. Entfernen Sie nicht die vom vorherigen Schritt generierten Präprozessordirektiven (#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 Microsoft Entra 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 (Microsoft Entra tenant issuing token), and resource (API being accessed; "aud" claim).
             const std::shared_ptr<void>& context,      // Opaque context passed by the host application through the MIP API
             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 generierte auth_delegate Klassenimplementierung durch die folgende Quelle ersetzen. Entfernen Sie die vom vorherigen Schritt generierten Präprozessordirektiven nicht (#pragma, #include).

      Von Bedeutung

      Der folgende Tokenakquisitionscode eignet sich nicht für die Produktionsverwendung. Ersetzen Sie dies in der Produktion durch Code, der dynamisch ein Token abruft, indem Sie Folgendes verwenden:

      • Der in Ihrer Microsoft Entra-App-Registrierung angegebene appId und der reply/redirect URI müssen Ihrer App-Registrierung entsprechen.
      • Die Autoritäts- und Ressourcen-URL, die vom SDK im challenge Argument übergeben wird (Ressourcen-URL muss mit der API/Berechtigungen Ihrer App-Registrierung übereinstimmen)
      • Gültige App-/Benutzeranmeldeinformationen, bei denen das Konto mit dem identity argument übereinstimmt, das vom SDK übergeben wird. OAuth2-"native"-Clients oder -Anwendungen sollten zur Eingabe von Benutzeranmeldeinformationen auffordern und den „Autorisierungscode-Ablauf“ 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.

      Der OAuth2-Tokenerwerb ist ein komplexes Protokoll und wird normalerweise mithilfe einer Bibliothek durchgeführt. TokenAcquireOAuth2Token() wird nur vom MIP SDK aufgerufen, sofern erforderlich.

      #include <iostream>
      using std::cout;
      using std::cin;
      using std::string;
      
      bool AuthDelegateImpl::AcquireOAuth2Token(const mip::Identity& identity, const OAuth2Challenge& challenge, const std::shared_ptr<void>& context, OAuth2Token& token) 
      {
           (void)context;
           // 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 (Buildlösung), um eine Testkompilierung/Verknüpfung Ihrer Lösung auszuführen, um sicherzustellen, dass sie erfolgreich erstellt wird, bevor Sie fortfahren.

Erstellen Sie nun eine Implementierung für einen Zustimmungsdelegat, indem Sie die Klasse des mip::ConsentDelegate SDK erweitern und die mip::AuthDelegate::GetUserConsent() reine virtuelle Funktion außer Kraft setzen oder implementieren. Die File-Profil- und File-Engine-Objekten instanziieren und verwenden den Einwilligungsdelegaten später.

  1. Fügen Sie mit dem zuvor verwendeten Visual Studio-Feature "Klasse hinzufügen" Ihrem Projekt eine weitere Klasse hinzu. Geben Sie dieses Mal "consent_delegate" in das Feld "Klassenname " ein.

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

    • Aktualisieren Sie "consent_delegate.h", indem Sie den gesamten generierten consent_delegate Klassencode durch die folgende Quelle ersetzen. Entfernen Sie nicht die vom vorherigen Schritt generierten Präprozessordirektiven (#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 alle generierten consent_delegate Klassenimplementierungen durch die folgende Quelle ersetzen. Entfernen Sie die vom vorherigen Schritt generierten Präprozessordirektiven nicht (#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 (Buildlösung), um eine Testkompilierung/Verknüpfung Ihrer Lösung auszuführen, um sicherzustellen, dass sie erfolgreich erstellt wird, bevor Sie fortfahren.

Erstellen eines Dateienprofils und einer Engine

Wie erwähnt, erfordern SDK-Clients, die MIP-APIs verwenden, Profil- und Modulobjekte. Schließen Sie den Codierungsteil dieser Schnellstartanleitung ab, indem Sie Code hinzufügen, um die Profil- und Modulobjekte zu instanziieren:

  1. Öffnen Sie im Projektmappen-Explorer die datei .cpp in Ihrem Projekt, die die Implementierung der main() Methode enthält. Standardmäßig wird derselbe Name wie das Projekt verwendet, das es enthält, das Sie während der Projekterstellung angegeben haben.

  2. Entfernen Sie die generierte Implementierung von main(). Entfernen Sie während der Projekterstellung (#pragma, #include) von Visual Studio generierte Präprozessordirektiven nicht. Fügen Sie den folgenden Code nach allen Präprozessordirektiven 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,
                                                                                                    mip::CacheStorageType::OnDisk);


  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 im Quellcode, den Sie mithilfe von Zeichenfolgenkonstanten eingefügt haben:

    Platzhalter Wert Example
    <application-id> Die Microsoft Entra Anwendungs-ID (GUID), die der Anwendung zugewiesen ist, die in Schritt 2 des Artikels "MIP SDK-Setup und -Konfiguration" registriert ist. Ersetzen Sie zwei Vorkommen. "00001111-aaaa-2222-bbbb-3333cccc4444"
    <Anwendungsname> Ein benutzerdefinierter freundlicher Name für Ihre Anwendung. Muss gültige ASCII-Zeichen (mit Ausnahme von ';') enthalten und entspricht idealerweise dem Anwendungsnamen, den Sie in Ihrer Microsoft Entra-Registrierung verwendet haben. "AppInitialization"
    <Anwendungsversion> Benutzerdefinierte Versionsinformationen für Ihre Anwendung. Muss gültige ASCII-Zeichen enthalten (mit Ausnahme von ';'). "1.1.0.0"
    <Engine-Konto> Das Konto, das für die Identität der Engine verwendet wird. Wenn Sie sich während des Tokenerwerbs mit einem Benutzerkonto authentifizieren, muss er diesem Wert entsprechen. "user1@tenant.onmicrosoft.com"
    <Modulzustand> Benutzerdefinierter Zustand, der mit der Engine verknüpft werden soll. "My App State"
  2. Führen Sie einen endgültigen Build der Anwendung aus, und beheben Sie alle Fehler. Ihr Code sollte erfolgreich erstellt werden, aber noch nicht ordnungsgemäß ausgeführt werden. Sie haben kein Zugriffstoken, das Sie angeben können, bevor Sie den nächsten Quickstart abgeschlossen haben.

Nächste Schritte

Nun, da Ihr Initialisierungscode vollständig ist, sind Sie bereit für die nächste Schnellstartanleitung, in der Sie erste Erfahrungen mit den MIP File SDKs sammeln.