Rychlý start: Inicializace klientské aplikace (C++)

V tomto rychlém startu se dozvíte, jak implementovat model inicializace klienta, který sada MIP C++ SDK používá za běhu.

Poznámka:

Každá klientská aplikace, která používá sady SDK MIP File, Policy nebo Protection, vyžaduje kroky popsané v tomto rychlém startu. Přestože tento rychlý úvod demonstruje použití sady File SDK, stejný postup lze použít i u klientů využívajících sady SDK pro zásady a ochranu. Dokončete zbývající rychlé starty sériově, protože každý z nich vychází z předchozího, přičemž první z nich je.

Požadavky

Pokud jste to ještě neudělali, nezapomeňte:

  • Dokončete kroky v nastavení a konfiguraci sady Microsoft Information Protection (MIP) SDK. Tento rychlý start "Inicializace klientské aplikace" spoléhá na správné nastavení a konfiguraci sady SDK.
  • Volitelně:
    • Zkontrolujte objekty profilu a modulu. Objekty profilu a engine jsou univerzální koncepty vyžadované klienty, kteří používají sady SDK MIP File/Policy/Protection.
    • Projděte si koncepty ověřování a zjistěte, jak sada SDK a klientská aplikace implementují ověřování a souhlas.
    • Projděte si koncepty Observeru a dozvíte se více o observorech a o tom, jak jsou implementovány. Sada MIP SDK používá vzor pozorovatele k implementaci asynchronních oznámení událostí.

Vytvoření řešení a projektu sady Visual Studio

Nejprve vytvořte a nakonfigurujte počáteční Visual Studio řešení a projekt, na kterém se ostatní rychlé starty sestavují.

  1. Otevřete Visual Studio 2022 nebo novější, vyberte nabídku Soubor , Nový, Projekt. V dialogovém okně Nový projekt :

    • V levém podokně v části Nainstalováno, Další jazyky vyberte Visual C++.

    • V prostředním podokně vyberte Konzolová aplikace systému Windows.

    • V dolním podokně odpovídajícím způsobem aktualizujte název projektu, umístění a obsahující název řešení .

    • Po dokončení klikněte na tlačítko OK v pravém dolním rohu.

      Vytvoření řešení v aplikaci Visual Studio.

  2. Do projektu přidejte balíček NuGet pro sadu MIP File SDK:

    • V Průzkumníku řešení klikněte pravým tlačítkem na uzel projektu (přímo pod horním uzlem nebo uzel řešení) a vyberte Spravovat balíčky NuGet...:

    • Když se karta Správce balíčků NuGet otevře v oblasti skupiny karet editoru:

      • Vyberte Procházet.
      • Do vyhledávacího pole zadejte "Microsoft.InformationProtection".
      • Vyberte balíček Microsoft.InformationProtection.File.
      • Pokud se zobrazí potvrzovací dialogové okno Náhled změn, nejprve klikněte na "Instalovat" a poté na "OK".

      Visual Studio – přidat balíček NuGet.

Implementujte třídu pozorovatele pro sledování profilu souboru a objektů enginu

Teď vytvořte základní implementaci třídy pozorovatele profilu souboru rozšířením třídy sady SDK mip::FileProfile::Observer . Později vytvoříte instanci observeru a použijete ji ke sledování načítání objektu File profile a přidání objektu enginu do profilu.

  1. Přidejte do projektu novou třídu, která za vás vygeneruje soubory header/.h i implementace/.cpp:

    • V Průzkumníku řešení znovu klikněte pravým tlačítkem myši na uzel projektu, vyberte Přidat a pak vyberte Třída.

    • V dialogovém okně Přidat třídu :

      • Do pole Název třídy zadejte "profile_observer". Všimněte si, že se automaticky vyplní pole souboru .h i .cpp na základě zadaného názvu.
      • Po dokončení klikněte na tlačítko OK .

      Visual Studio – přidání třídy.

  2. Po vygenerování souborů .h a .cpp pro třídu Visual Studio otevře oba soubory na kartách Skupina editoru. Teď aktualizujte každý soubor tak, aby implementovali novou třídu pozorovatele:

    • Aktualizujte "profile_observer.h" tak, že vyberete nebo odstraníte vygenerovanou profile_observer třídu. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#pragma, #include). Potom zkopírujte/vložte následující zdroj do souboru za všechny existující direktivy preprocesoru:

      #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;
      };
      
    • Aktualizujte "profile_observer.cpp" výběrem nebo odstraněním vygenerované profile_observer implementace třídy. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#pragma, #include). Potom zkopírujte/vložte následující zdroj do souboru za všechny existující direktivy preprocesoru:

      #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. Volitelně můžete pomocí F6 (sestavit řešení) spustit testovací kompilaci nebo propojení vašeho řešení, abyste se ujistili, že se sestavení úspěšně sestaví, než budete pokračovat.

Implementujte delegáta ověřování

Sada MIP SDK implementuje ověřování pomocí rozšiřitelnosti tříd, která poskytuje mechanismus sdílení ověřování s klientskou aplikací. Klient musí získat vhodný přístupový token OAuth2 a poskytnout ho sadě MIP SDK za běhu.

Nyní vytvořte implementaci delegáta pro ověřování rozšířením třídy mip::AuthDelegate ze sady SDK a přepsáním nebo implementací čistě virtuální funkce mip::AuthDelegate::AcquireOAuth2Token(). Objekt Profile souboru a objekty modulu File engine později vytvoří instanci ověřovacího delegáta a použijí ji.

  1. Pomocí stejné funkce Přidat třídu v sadě Visual Studio, kterou jsme použili v kroku 1 předchozí části, přidejte do projektu další třídu. Tentokrát do pole Název třídy zadejte "auth_delegate".

  2. Teď aktualizujte každý soubor tak, aby implementovali novou třídu delegáta ověřování:

    • Aktualizujte "auth_delegate.h" nahrazením veškerého vygenerovaného auth_delegate kódu třídy následujícím zdrojem. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#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;
      };
      
    • Aktualizujte "auth_delegate.cpp" nahrazením všech vygenerovaných auth_delegate implementací třídy následujícím zdrojem. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#pragma, #include).

      Důležité

      Následující kód získání tokenu není vhodný pro použití v produkčním prostředí. V produkčním prostředí ho nahraďte kódem, který dynamicky získává token pomocí:

      • Id aplikace a identifikátor URI pro odpověď/přesměrování zadaný v registraci aplikace Microsoft Entra (odpověď/identifikátor URI přesměrování musí odpovídat vaší registraci aplikace)
      • Adresa URL autority a zdroje předaná sadou SDK v argumentu challenge (adresa URL zdroje musí přesně odpovídat rozhraní API a oprávněním registrace vaší aplikace)
      • Platné přihlašovací údaje aplikace/uživatele, kde účet odpovídá argumentu identity předaného sadou SDK. Nativní klienti OAuth2 by měli vyzvat k zadání přihlašovacích údajů uživatele a použít tok autorizačního kódu. "Důvěrné klienty" OAuth2 můžou používat vlastní zabezpečené přihlašovací údaje s tokem "přihlašovacích údajů klienta" (jako je služba) nebo zobrazit výzvu k zadání přihlašovacích údajů uživatele pomocí toku "autorizačního kódu" (například webové aplikace).

      Získání tokenu OAuth2 je složitý protokol a obvykle se dosahuje pomocí knihovny. TokenAcquireOAuth2Token() je volána sadou MIP SDK pouze, jak je požadováno.

      #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. Volitelně můžete pomocí F6 (sestavit řešení) spustit testovací kompilaci nebo propojení vašeho řešení, abyste se ujistili, že se sestavení úspěšně sestaví, než budete pokračovat.

Nyní vytvořte implementaci delegáta souhlasu rozšířením třídy mip::ConsentDelegate ze sady SDK a přepsáním nebo implementací čistě virtuální funkce mip::AuthDelegate::GetUserConsent(). Objekt File profile a objekty File engine vytvoří instanci delegáta pro souhlas a později jej použijí.

  1. Pomocí stejné funkce Přidat třídu sady Visual Studio, kterou jsme použili dříve, přidejte do projektu další třídu. Tentokrát do pole Název třídy zadejte "consent_delegate".

  2. Teď aktualizujte každý soubor tak, aby implementovali novou třídu delegáta souhlasu:

    • Aktualizujte "consent_delegate.h" nahrazením veškerého vygenerovaného consent_delegate kódu třídy následujícím zdrojem. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#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;
      };
      
    • Aktualizujte "consent_delegate.cpp" nahrazením všech vygenerovaných consent_delegate implementací třídy následujícím zdrojem. Neodebíjejte direktivy preprocesoru generované předchozím krokem (#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. Volitelně můžete pomocí F6 (sestavit řešení) spustit testovací kompilaci nebo propojení vašeho řešení, abyste se ujistili, že se sestavení úspěšně sestaví, než budete pokračovat.

Konstrukce profilu souboru a jádra

Jak už bylo zmíněno, klienti sady SDK, kteří používají rozhraní API MIP, vyžadují objekty profilu a modulu. Dokončete část kódu tohoto rychlého startu přidáním kódu pro vytvoření instance objektů profilu a modulu:

  1. V Průzkumníku řešení otevřete soubor .cpp v projektu, který obsahuje implementaci main() metody. V rámci výchozího nastavení se použije stejný název jako projekt, který ho obsahuje a který jste zadali při vytváření projektu.

  2. Odeberte vygenerovanou implementaci main(). Při vytváření projektu neodebívejte direktivy preprocesoru generované sadou Visual Studio (#pragma, #include). Za všechny direktivy preprocesoru připojte následující kód:

#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. Nahraďte všechny zástupné hodnoty ve zdrojovém kódu, které jste vložili pomocí řetězcových konstant:

    Zástupný text Hodnota Příklad
    <ID aplikace> ID Microsoft Entra aplikace (GUID) přiřazené k aplikaci zaregistrované v kroku 2 článku Nastavení a konfigurace sady MIP SDK. Nahraďte 2 instance. "00001111-aaaa-2222-bbbb-3333cccc4444"
    <název aplikace> Uživatelsky definovaný popisný název aplikace. Musí obsahovat platné znaky ASCII (s výjimkou ;) a v ideálním případě se shoduje s názvem aplikace, který jste použili v registraci Microsoft Entra. "AppInitialization"
    <verze aplikace> Informace o verzi definované uživatelem pro vaši aplikaci Musí obsahovat platné znaky ASCII (s výjimkou ;). "1.1.0.0"
    <účet pro engine> Účet použitý pro identitu modulu. Při ověřování pomocí uživatelského účtu během získávání tokenů se musí shodovat s touto hodnotou. "user1@tenant.onmicrosoft.com"
    <stav motoru> Uživatelem definovaný stav, který se má přidružit k zařízení. "My App State"
  2. Proveďte konečné sestavení aplikace a vyřešte případné chyby. Kód by se měl úspěšně sestavit, ale ještě se nespustí správně. Dokud nedokončíte další rychlý start, nemáte přístupový token k zadání.

Další kroky

Teď, když je inicializační kód hotový, jste připraveni na další rychlý start, kde začnete používat sady MIP File SDK.