Snabbstart: Initiering av klientprogram (C++)

Den här snabbstarten visar hur du implementerar mönstret för klientinitiering som används av MIP C++ SDK vid körning.

Kommentar

De steg som beskrivs i den här snabbstarten krävs för alla klientprogram som använder SDK:er för MIP-filer, principer eller skydd. Även om den här snabbstarten visar hur fil-SDK:erna används, gäller samma mönster för klienter som använder SDK:er för princip och skydd. Slutför de återstående snabbstarterna seriellt, eftersom var och en bygger på den föregående, där den här är den första.

Förutsättningar

Om du inte redan har gjort det måste du:

  • Slutför stegen i Konfiguration och konfiguration av Microsoft Information Protection (MIP) SDK. Den här snabbstarten "Klientprograminitiering" förlitar sig på korrekt SDK-konfiguration.
  • Valfritt:
    • Granska profil- och motorobjekt. Profil- och motorobjekten är universella begrepp som krävs av klienter som använder SDK:er för MIP-fil/princip/skydd.
    • Läs Autentiseringsbegrepp för att lära dig hur autentisering och medgivande implementeras av SDK och klientprogrammet.
    • Läs Observer-begrepp för att lära dig mer om observatörer och hur de implementeras. MIP SDK använder övervakningsmönstret för att implementera asynkrona händelsemeddelanden.

Skapa en Visual Studio-lösning och ett projekt

Först skapar och konfigurerar vi den första Visual Studio-lösningen och projektet, som de andra snabbstarterna bygger på.

  1. Öppna Visual Studio 2017, välj menyn Arkiv , Nytt, Projekt. I dialogrutan Nytt projekt:

    • I den vänstra rutan, under Installerat, Andra språk, väljer du Visual C++.

    • I mittenfönstret väljer du Windows-konsolprogram

    • I den nedre rutan uppdaterar du projektets namn, plats och det innehållande lösningsnamnet i enlighet med detta.

    • När du är klar klickar du på OK-knappen längst ned till höger.

      Visual Studio solution creation

  2. Lägg till Nuget-paketet för MIP File SDK i projektet:

    • I Solution Explorer högerklickar du på projektnoden (direkt under den övre noden/lösningsnoden) och väljer Hantera NuGet-paket...:

    • När fliken NuGet Package Manager öppnas i området Redigerargruppflikar:

      • Välj bläddra.
      • Ange "Microsoft.InformationProtection" i sökrutan.
      • Välj paketet "Microsoft.InformationProtection.File".
      • Klicka på "Installera" och sedan på "OK" när bekräftelsedialogrutan Förhandsgranskningsändringar visas.

      Visual Studio add NuGet package

Implementera en observatörsklass för att övervaka objekten Filprofil och motor

Skapa nu en grundläggande implementering för en filprofilobservatörsklass genom att utöka SDK:ts mip::FileProfile::Observer klass. Observatören instansieras och används senare för att övervaka inläsningen av filprofilobjektet och lägga till motorobjektet i profilen.

  1. Lägg till en ny klass i projektet, som genererar både huvud-/.h- och implementeringsfilerna/.cpp åt dig:

    • I Solution Explorer högerklickar du på projektnoden igen, väljer Lägg till och väljer sedan Klass.

    • I dialogrutan Lägg till klass:

      • I fältet Klassnamn anger du "profile_observer". Observera att både .h-filen och .cpp-filfälten fylls i automatiskt, baserat på det namn du anger.
      • När du är klar klickar du på ok-knappen .

      Visual Studio add class

  2. När du har genererat .h- och .cpp-filerna för klassen öppnas båda filerna på flikarna Redigerargrupp. Uppdatera nu varje fil för att implementera din nya observatörsklass:

    • Uppdatera "profile_observer.h" genom att välja/ta bort den genererade profile_observer klassen. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#pragma, #include). Kopiera/klistra sedan in följande källa i filen efter befintliga förprocessordirektiv:

      #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;
      };
      
    • Uppdatera "profile_observer.cpp" genom att välja/ta bort den genererade profile_observer klassimplementeringen. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#pragma, #include). Kopiera/klistra sedan in följande källa i filen efter befintliga förprocessordirektiv:

      #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. Du kan också använda F6 (Build Solution) för att köra en testkompilering/länk för din lösning för att se till att den skapas korrekt innan du fortsätter.

Implementera en autentiseringsdelegat

MIP SDK implementerar autentisering med hjälp av utökningsbarhet för klassen, vilket ger en mekanism för att dela autentiseringsarbete med klientprogrammet. Klienten måste hämta en lämplig OAuth2-åtkomsttoken och tillhandahålla MIP SDK vid körning.

Skapa nu en implementering för ett autentiseringsdelegat genom att utöka SDK:ts mip::AuthDelegate klass och åsidosätta/implementera den mip::AuthDelegate::AcquireOAuth2Token() rena virtuella funktionen. Autentiseringsdelegaten instansieras och används senare av objekten Filprofil och Filmotor.

  1. Med samma Visual Studio-funktion "Lägg till klass" som vi använde i steg 1 i föregående avsnitt lägger du till ytterligare en klass i projektet. Den här gången anger du "auth_delegate" i fältet Klassnamn .

  2. Uppdatera nu varje fil för att implementera din nya autentiseringsdelegatklass:

    • Uppdatera "auth_delegate.h" genom att ersätta all genererad auth_delegate klasskod med följande källa. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#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;
      };
      
    • Uppdatera "auth_delegate.cpp" genom att ersätta all genererad auth_delegate klassimplementering med följande källa. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#pragma, #include).

      Viktigt!

      Följande tokeninsamlingskod är inte lämplig för produktionsanvändning. I produktion måste detta ersättas med kod som dynamiskt hämtar en token med hjälp av:

      • AppId och svars-/omdirigerings-URI som anges i din Microsoft Entra-appregistrering (svars-/omdirigerings-URI måste matcha din appregistrering)
      • Utfärdaren och resurs-URL:en som skickades av SDK:n i challenge argumentet (resurs-URL:en måste matcha appregistreringens API/behörigheter)
      • Giltiga autentiseringsuppgifter för app/användare, där kontot matchar argumentet identity som skickas av SDK:t. OAuth2-klienter bör fråga efter användarautentiseringsuppgifter och använda flödet "auktoriseringskod". OAuth2 "konfidentiella klienter" kan använda sina egna säkra autentiseringsuppgifter med flödet "klientautentiseringsuppgifter" (till exempel en tjänst) eller fråga efter användarautentiseringsuppgifter med hjälp av flödet "auktoriseringskod" (till exempel en webbapp).

      OAuth2-tokenförvärv är ett komplext protokoll som normalt utförs med hjälp av ett bibliotek. TokenAcquireOAuth2Token() anropas endast av MIP SDK efter behov.

      #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. Du kan också använda F6 (Build Solution) för att köra en testkompilering/länk för din lösning för att se till att den skapas korrekt innan du fortsätter.

Skapa nu en implementering för ett medgivandedelegat genom att utöka SDK:ts mip::ConsentDelegate klass och åsidosätta/implementera den mip::AuthDelegate::GetUserConsent() rena virtuella funktionen. Medgivandedelegaten instansieras och används senare av objekten Filprofil och Filmotor.

  1. Med samma Visual Studio-funktion "Lägg till klass" som vi använde tidigare lägger du till en annan klass i projektet. Den här gången anger du "consent_delegate" i fältet Klassnamn .

  2. Uppdatera nu varje fil för att implementera din nya medgivandedelegatklass:

    • Uppdatera "consent_delegate.h" genom att ersätta all genererad consent_delegate klasskod med följande källa. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#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;
      };
      
    • Uppdatera "consent_delegate.cpp" genom att ersätta all genererad consent_delegate klassimplementering med följande källa. Ta inte bort de förprocessordirektiv som genererades av föregående steg (#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. Du kan också använda F6 (Build Solution) för att köra en testkompilering/länk för din lösning för att se till att den skapas korrekt innan du fortsätter.

Skapa en filprofil och motor

Som nämnts krävs profil- och motorobjekt för SDK-klienter med hjälp av MIP-API:er. Slutför kodningsdelen av den här snabbstarten genom att lägga till kod för att instansiera profil- och motorobjekten:

  1. Öppna .cpp-filen i projektet som innehåller implementeringen av main() metoden från Solution Explorer. Det är som standard samma namn som det projekt som innehåller det, som du angav när projektet skapades.

  2. Ta bort den genererade implementeringen av main(). Ta inte bort förprocessordirektiv som genereras av Visual Studio när projektet skapas (#pragma, #include). Lägg till följande kod efter eventuella förprocessordirektiv:

#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. Ersätt alla platshållarvärden i källkoden som du precis klistrade in med hjälp av strängkonstanter:

    Platshållare Värde Exempel
    <application-id> Microsoft Entra-program-ID (GUID) som tilldelats det program som registrerats i steg 2 i artikeln "Konfiguration och konfiguration av MIP SDK" . Ersätt 2 instanser. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <programnamn> Ett användardefinierat eget namn för ditt program. Måste innehålla giltiga ASCII-tecken (exklusive ';') och matchar helst det programnamn som du använde i din Microsoft Entra-registrering. "AppInitialization"
    <programversion> Användardefinierad versionsinformation för ditt program. Måste innehålla giltiga ASCII-tecken (exklusive ';'). "1.1.0.0"
    <engine-account> Det konto som används för motorns identitet. När du autentiserar med ett användarkonto under tokenförvärvet måste det matcha det här värdet. "user1@tenant.onmicrosoft.com"
    <motortillstånd> Användardefinierat tillstånd som ska associeras med motorn. "My App State"
  2. Gör nu en slutlig version av programmet och lös eventuella fel. Koden bör byggas korrekt, men den kommer inte att köras korrekt förrän du har slutfört nästa snabbstart. Om du kör programmet visas utdata som liknar följande. Du har ingen åtkomsttoken att ange förrän du har slutfört nästa snabbstart.

Nästa steg

Nu när initieringskoden är klar är du redo för nästa snabbstart, där du börjar uppleva MIP-fil-SDK:erna.