Guida introduttiva: Inizializzazione delle applicazioni client (C++)Quickstart: Client application initialization (C++)

Questo avvio rapido spiega come implementare il modello di inizializzazione client usato dal SDK C++ di MIP in fase di esecuzione.This quickstart shows you how to implement the client initialization pattern, used by the MIP C++ SDK at runtime.

Nota

I passaggi descritti in questa guida introduttiva sono necessari per qualsiasi applicazione client che usa le API File, Criteri e Protezione di MIP.The steps outlined in this quickstart are required for any client application that uses the MIP File, Policy, or Protection APIs. Sebbene questa guida introduttiva illustri l'utilizzo delle API File, lo stesso modello è applicabile ai client che usano le API Criteri e Protezione.Although this Quickstart demonstrates usage of the File APIs, this same pattern is applicable to clients using the Policy and Protection APIs. Gli avvii rapidi successivi devono essere eseguiti in sequenza, perché ognuno è basato sul precedente e questo è il primo.Complete the remaining Quickstarts serially, as each one builds on the previous one, with this one being the first.

PrerequisitiPrerequisites

Se non è già stato fatto, assicurarsi di:If you haven't already, be sure to:

Creare una soluzione e un progetto di Visual StudioCreate a Visual Studio solution and project

Verranno prima di tutto creati e configurati la soluzione e il progetto iniziali di Visual Studio su cui si baseranno le altre procedure di avvio rapido.First we create and configure the initial Visual Studio solution and project, upon which the other Quickstarts build.

  1. Aprire Visual Studio 2017 e scegliere File, Nuovo, Progetto dal menu.Open Visual Studio 2017, select the File menu, New, Project. Nella finestra di dialogo Nuovo progetto:In the New Project dialog:

    • Nel riquadro sinistro, in Installati, Altri linguaggi, selezionare Visual C++ .In the left pane, under Installed, Other Languages, select Visual C++.

    • Nel riquadro centrale selezionare Applicazione console di Windows.In the center pane, select Windows Console Application

    • Nel riquadro inferiore, aggiornare Nome e Posizione del progetto, nonché il Nome della soluzione in cui è contenuto corrispondentemente.In the bottom pane, update the project Name, Location, and the containing Solution name accordingly.

    • Al termine fare clic sul pulsante OK in basso a destra.When finished, click the OK button in the lower right.

      Creazione di una soluzione Visual StudioVisual Studio solution creation

  2. Aggiungere il pacchetto NuGet per l'API File di MIP SDK al progetto:Add the Nuget package for the MIP SDK File API to your project:

    • In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto (subito sotto il nodo della soluzione principale) e scegliere Gestisci pacchetti NuGet:In the Solution Explorer, right-click the project node (directly under the top/solution node), and select Manage NuGet packages...:

    • Quando viene aperta la scheda Gestione pacchetti NuGet nell'area delle schede Gruppo di editor:When the NuGet Package Manager tab opens in the Editor Group tabs area:

      • Selezionare Sfoglia.Select Browse.
      • Immettere "Microsoft.InformationProtection" nella casella di ricerca.Enter "Microsoft.InformationProtection" in the search box.
      • Selezionare il pacchetto "Microsoft.InformationProtection.File".Select the "Microsoft.InformationProtection.File" package.
      • Fare clic su "Installa" e quindi su "OK" quando viene visualizzata la finestra di dialogo di conferma Anteprima modifiche.Click "Install", then click "OK" when the Preview changes confirmation dialog displays.

      Aggiunta del pacchetto NuGet in Visual StudioVisual Studio add NuGet package

Implementare una classe osservatore per monitorare gli oggetti profilo e motore dell'API FileImplement an observer class to monitor the File profile and engine objects

Creare ora un'implementazione di base per una classe osservatore per il profilo File mediante l'estensione della classe mip::FileProfile::Observer dell'SDK.Now create a basic implementation for a File profile observer class, by extending the SDK's mip::FileProfile::Observer class. In seguito si creerà e userà un'istanza dell'osservatore per monitorare il caricamento dell'oggetto profilo File e l'aggiunta dell'oggetto motore al profilo.The observer is instantiated and used later, to monitor the loading of the File profile object, and adding the engine object to the profile.

  1. Aggiungere una nuova classe al progetto, che genera automaticamente i file header/.h e implementation/.cpp:Add a new class to your project, which generates both the header/.h and implementation/.cpp files for you:

    • In Esplora soluzioni fare di nuovo clic con il pulsante destro del mouse sul nodo del progetto e scegliere Aggiungi, quindi scegliere Classe.In the Solution Explorer, right-click the project node again, select Add, then select Class.

    • Nella finestra di dialogo Aggiungi classe:On the Add Class dialog:

      • Nel campo Nome classe immettere "profile_observer".In the Class Name field, enter "profile_observer". Si noti che i campi del file con estensione h e del file con estensione cpp vengono popolati automaticamente in base al nome immesso.Notice that both the .h file and .cpp file fields are automatically populated, based on the name you enter.
      • Al termine fare clic su OK.When finished, click the OK button.

      Aggiunta della classe in Visual StudioVisual Studio add class

  2. Dopo la generazione dei file con estensione h e cpp per la classe, entrambi i file vengono aperti nelle schede Editor gruppo.After generating the .h and .cpp files for the class, both files are opened in Editor Group tabs. A questo punto aggiornare ogni file per implementare la nuova classe observer:Now update each file to implement your new observer class:

    • Aggiornare "profile_observer.h" selezionando ed eliminando la classe profile_observer generata.Update "profile_observer.h", by selecting/deleting the generated profile_observer class. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include).Don't remove the preprocessor directives generated by the previous step (#pragma, #include). Quindi copiare e incollare la seguente origine nel file, dopo le eventuali direttive del preprocessore esistenti:Then copy/paste the following source into the file, after any existing preprocessor directives:

      #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;
      };
      
    • Aggiornare "profile_observer.cpp", selezionando ed eliminando l'implementazione della classe profile_observer generata.Update "profile_observer.cpp", by selecting/deleting the generated profile_observer class implementation. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include).Don't remove the preprocessor directives generated by the previous step (#pragma, #include). Quindi copiare e incollare la seguente origine nel file, dopo le eventuali direttive del preprocessore esistenti:Then copy/paste the following source into the file, after any existing preprocessor directives:

      #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. Facoltativamente, usare F6 (Compila soluzione) per eseguire una compilazione/collegamento di prova della soluzione e assicurarsi che venga compilata correttamente prima di continuare.Optionally, use F6 (Build Solution) to run a test compile/link of your solution, to make sure it builds successfully before continuing.

Implementare un delegato di autenticazioneImplement an authentication delegate

MIP SDK implementa l'autenticazione usando l'estensibilità delle classi, che rende disponibile un meccanismo per condividere le operazioni di autenticazione con l'applicazione client.The MIP SDK implements authentication using class extensibility, which provides a mechanism to share authentication work with the client application. Il client deve acquisire un token di accesso OAuth2 adatto e fornirlo a MIP SDK in fase di esecuzione.The client must acquire a suitable OAuth2 access token, and provide to the MIP SDK at runtime.

Si creerà ora un'implementazione per un delegato di autenticazione mediante l'estensione della classe mip::AuthDelegate dell'SDK e l'override/implementazione della funzione virtuale pura mip::AuthDelegate::AcquireOAuth2Token().Now create an implementation for an authentication delegate, by extending the SDK's mip::AuthDelegate class, and overriding/implementing the mip::AuthDelegate::AcquireOAuth2Token() pure virtual function. In seguito si creerà un'istanza del delegato di autenticazione che verrà usata dagli oggetti profilo e motore dell'API File.The authentication delegate is instantiated and used later, by the File profile and File engine objects.

  1. Usando la stessa funzionalità "Aggiungi classe" di Visual Studio usata nel passaggio 1 della sezione precedente, aggiungere un'altra classe al progetto.Using the same Visual Studio "Add Class" feature we used in step #1 of the previous section, add another class to your project. Questa volta, immettere "auth_delegate" nel campo Nome classe.This time, enter "auth_delegate" in the Class Name field.

  2. A questo punto aggiornare ogni file per implementare la nuova classe del delegato di autenticazione:Now update each file to implement your new authentication delegate class:

    • Aggiornare "auth_delegate.h" sostituendo tutto il codice della classe auth_delegate generato con il codice sorgente seguente.Update "auth_delegate.h", by replacing all of the generated auth_delegate class code with the following source. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include):Don't remove the preprocessor directives generated by the previous step (#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;
      };
      
    • Aggiornare "auth_delegate.cpp" sostituendo tutto il codice dell'implementazione della classe auth_delegate generato con il codice sorgente seguente.Update "auth_delegate.cpp", by replacing all of the generated auth_delegate class implementation with the following source. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include).Don't remove the preprocessor directives generated by the previous step (#pragma, #include).

      Importante

      Il codice di acquisizione del token seguente non è adatto per l'uso in ambiente di produzione.The following token acquisition code is not suitable for production use. Nell'ambiente di produzione questo deve essere sostituito da codice che acquisisce in modo dinamico un token, usando:In production, this must be replaced by code that dynamically acquires a token, using:

      • AppId e URI di risposta/reindirizzamento specificati nella registrazione dell'app di Azure AD (l'URI di risposta/reindirizzamento deve corrispondere alla registrazione dell'app)The appId and reply/redirect URI specified in your Azure AD app registration (reply/redirect URI must match your app registration)
      • L'URL dell'autorità e della risorsa passato dall'SDK nell'argomento challenge (l'URL della risorsa deve corrispondere ad API/autorizzazioni della registrazione dell'app)The authority and resource URL passed by the SDK in the challenge argument (resource URL must match your app registration's API/permissions)
      • Credenziali valide per app/utente, in cui l'account corrisponde all'argomento identity passato dall'SDK.Valid app/user credentials, where the account matches the identity argument passed by the SDK. I client "nativi" OAuth2 devono richiedere le credenziali utente e usare il flusso di "codice di autorizzazione".OAuth2 "native" clients should prompt for user credentials and use the "authorization code" flow. I "client riservati" OAuth2 possono usare le proprie credenziali protette con il flusso di "credenziali client" (ad esempio, un servizio) o richiedere le credenziali utente usando il flusso di "codice di autorizzazione" (ad esempio, un'app Web).OAuth2 "confidential clients" can use their own secure credentials with the "client credentials" flow (such as a service), or prompt for user credentials using the "authorization code" flow (such as a web app).

      L'acquisizione di token OAuth2 è un protocollo complesso e in genere viene eseguita usando una libreria.OAuth2 token acquisition is a complex protocol, and normally accomplished by using a library. La funzione TokenAcquireOAuth2Token() viene chiamata solo da MIP SDK, all'occorrenza.TokenAcquireOAuth2Token() is called only by the MIP SDK, as required.

      #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. Facoltativamente, usare F6 (Compila soluzione) per eseguire una compilazione/collegamento di prova della soluzione e assicurarsi che venga compilata correttamente prima di continuare.Optionally, use F6 (Build Solution) to run a test compile/link of your solution, to make sure it builds successfully before continuing.

Si creerà ora un'implementazione per un delegato di consenso mediante l'estensione della classe mip::ConsentDelegate dell'SDK e l'override/implementazione della funzione virtuale pura mip::AuthDelegate::GetUserConsent().Now create an implementation for a consent delegate, by extending the SDK's mip::ConsentDelegate class, and overriding/implementing the mip::AuthDelegate::GetUserConsent() pure virtual function. In seguito si creerà un'istanza del delegato di consenso che verrà usata dagli oggetti profilo e motore dell'API File.The consent delegate is instantiated and used later, by the File profile and File engine objects.

  1. Usando la stessa funzionalità "Aggiungi classe" di Visual Studio usata in precedenza, aggiungere un'altra classe al progetto.Using the same Visual Studio "Add Class" feature we used previously, add another class to your project. Questa volta, immettere "consent_delegate" nel campo Nome classe.This time, enter "consent_delegate" in the Class Name field.

  2. A questo punto aggiornare ogni file per implementare la nuova classe del delegato di consenso:Now update each file to implement your new consent delegate class:

    • Aggiornare "consent_delegate.h" sostituendo tutto il codice della classe consent_delegate generato con il codice sorgente seguente.Update "consent_delegate.h", by replacing all of the generated consent_delegate class code with the following source. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include):Don't remove the preprocessor directives generated by the previous step (#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;
      };
      
    • Aggiornare "consent_delegate.cpp" sostituendo tutto il codice dell'implementazione della classe consent_delegate generato con il codice sorgente seguente.Update "consent_delegate.cpp", by replacing all of the generated consent_delegate class implementation with the following source. Non rimuovere le direttive del preprocessore generate nel passaggio precedente (#pragma, #include).Don't remove the preprocessor directives generated by the previous step (#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. Facoltativamente, usare F6 (Compila soluzione) per eseguire una compilazione/collegamento di prova della soluzione e assicurarsi che venga compilata correttamente prima di continuare.Optionally, use F6 (Build Solution) to run a test compile/link of your solution, to make sure it builds successfully before continuing.

Costruire gli oggetti profilo e motore FileConstruct a File profile and engine

Come detto, gli oggetti profilo e motore sono necessari per i client del SDK che usano API MIP.As mentioned, profile and engine objects are required for SDK clients using MIP APIs. Completare la parte di scrittura del codice di questa guida introduttiva, aggiungendo il codice per creare un'istanza degli oggetti profilo e motore:Complete the coding portion of this Quickstart, by adding code to instantiate the profile and engine objects:

  1. Da Esplora soluzioni aprire il file con estensione cpp del progetto che contiene l'implementazione del metodo main().From Solution Explorer, open the .cpp file in your project that contains the implementation of the main() method. Per impostazione predefinita il file assume lo stesso nome del progetto che lo contiene, specificato dall'utente durante la creazione del progetto.It defaults to the same name as the project containing it, which you specified during project creation.

  2. Rimuovere l'implementazione generata di main().Remove the generated implementation of main(). Non rimuovere le direttive del preprocessore generate da Visual Studio durante la creazione del progetto (#pragma, #include).Don't remove preprocessor directives generated by Visual Studio during project creation (#pragma, #include). Aggiungere il codice seguente dopo eventuali direttive del preprocessore:Append the following code after any preprocessor directives:

    #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 appInfo{"<application-id>",                    // ApplicationInfo object (App ID, name, version)
                  "<application-name>",
                  "<application-version>"};
    
      auto mipContext = mip::MipContext::Create(appInfo,
                          "file_sample",
                          mip::LogLevel::Trace,
                          nullptr /*loggerDelegateOverride*/,
                          nullptr /*telemetryOverride*/);
    
      auto profileObserver = make_shared<ProfileObserver>();         // Observer object
      auto authDelegateImpl = make_shared<AuthDelegateImpl>(         // Authentication delegate object (App ID)
                  "<application-id>");
      auto consentDelegateImpl = make_shared<ConsentDelegateImpl>(); // Consent delegate object
    
      // Construct/initialize profile object
      FileProfile::Settings profileSettings(
        mipContext,
        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 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 = nullptr;
    
    return 0;
    }
    
  3. Sostituire tutti i valori segnaposto nel codice sorgente appena incollato, usando costanti stringa:Replace all placeholder values in the source code that you just pasted in, using string constants:

    SegnapostoPlaceholder ValoreValue EsempioExample
    <application-id> ID di applicazione (GUID) di Azure AD assegnato all'applicazione registrata nel passaggio 2 dell'articolo "Installazione e configurazione di MIP SDK".The Azure AD Application ID (GUID) assigned to the application registered in step #2 of the "MIP SDK setup and configuration" article. Sostituire 2 istanze.Replace 2 instances. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <application-name> Nome descrittivo definito dall'utente per l'applicazione.A user-defined friendly name for your application. Deve contenere caratteri ASCII validi (escluso ';') e idealmente corrisponde al nome dell'applicazione usato nella registrazione di Azure AD.Must contain valid ASCII characters (excluding ';'), and ideally matches the application name you used in your Azure AD registration. "AppInitialization"
    <application-version> Informazioni sulla versione definite dall'utente per l'applicazione.User-defined version info for your application. Deve contenere caratteri ASCII validi (escluso ';').Must contain valid ASCII characters (excluding ';'). "1.1.0.0"
    <engine-account> Account usato per l'identità del motore.The account used for the engine's identity. Quando si esegue l'autenticazione con un account utente durante l'acquisizione dei token, deve corrispondere a questo valore.When you authenticate with a user account during token acquisition, it must match this value. "user1@tenant.onmicrosoft.com"
    <engine-state> Stato definito dall'utente da associare al motore.User-defined state to be associated with the engine. "My App State"
  4. Eseguire ora la compilazione finale dell'applicazione e risolvere gli eventuali errori.Now do a final build of the application and resolve any errors. Il codice dovrebbe essere compilato correttamente, ma non verrà eseguito correttamente fino al completamento della guida introduttiva successiva.Your code should build successfully, but will not yet run correctly until you complete the next Quickstart. Se si esegue l'applicazione viene visualizzato un output simile al seguente.If you run the application, you see output similar to the following. Il token di accesso da specificare sarà disponibile solo dopo il completamento della guida introduttiva successiva.You won't have an access token to provide, until you complete the next Quickstart.

Passaggi successiviNext Steps

Ora che il codice di inizializzazione è completo, si è pronti per la guida introduttiva successiva, in cui si inizieranno a provare le API File MIP.Now that your initialization code is complete, you're ready for the next quickstart, where you'll start to experience the MIP File APIs.