Guia de início rápido: inicialização do aplicativo cliente (C++)

Este guia de início rápido mostra como implementar o padrão de inicialização do cliente, usado pelo MIP C++ SDK em tempo de execução.

Nota

As etapas descritas neste início rápido são necessárias para qualquer aplicativo cliente que use o arquivo MIP, a política ou os SDKs de proteção. Embora este Guia de início rápido demonstre o uso dos SDKs de arquivo, esse mesmo padrão é aplicável aos clientes que usam os SDKs de política e proteção. Complete os restantes Quickstarts em série, à medida que cada um se baseia no anterior, sendo este o primeiro.

Pré-requisitos

Se ainda não o fez, certifique-se de:

  • Conclua as etapas na instalação e configuração do SDK do Microsoft Information Protection (MIP). Este Guia de início rápido de "inicialização do aplicativo cliente" depende da instalação e configuração adequadas do SDK.
  • Opcionalmente:
    • Revise os objetos do perfil e do mecanismo. Os objetos de perfil e mecanismo são conceitos universais, exigidos por clientes que usam os SDKs de arquivo/política/proteção MIP.
    • Analise os conceitos de autenticação para saber como a autenticação e o consentimento são implementados pelo SDK e pelo aplicativo cliente.
    • Analise os conceitos do Observer para saber mais sobre os observadores e como eles são implementados. O MIP SDK usa o padrão de observador para implementar notificações de eventos assíncronas.

Criar uma solução e um projeto do Visual Studio

Primeiro, criamos e configuramos a solução e o projeto iniciais do Visual Studio, sobre os quais os outros Quickstarts são compilados.

  1. Abra o Visual Studio 2017, selecione o menu Arquivo , Novo, Projeto. Na caixa de diálogo Novo projeto:

    • No painel esquerdo, em Instalado, Outros Idiomas, selecione Visual C++.

    • No painel central, selecione Aplicativo de Console do Windows

    • No painel inferior, atualize o nome do projeto, o local e o nome da solução que o contém de acordo.

    • Quando terminar, clique no botão OK no canto inferior direito.

      Visual Studio solution creation

  2. Adicione o pacote Nuget para o MIP File SDK ao seu projeto:

    • No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto (diretamente abaixo do nó superior/solução) e selecione Gerenciar pacotes NuGet...:

    • Quando a guia Gerenciador de Pacotes NuGet for aberta na área de guias Grupo de Editores:

      • Selecione Procurar.
      • Digite "Microsoft.InformationProtection" na caixa de pesquisa.
      • Selecione o pacote "Microsoft.InformationProtection.File".
      • Clique em "Instalar" e, em seguida, clique em "OK" quando a caixa de diálogo de confirmação de alterações de visualização for exibida.

      Visual Studio add NuGet package

Implementar uma classe de observador para monitorar o perfil File e os objetos do mecanismo

Agora, crie uma implementação básica para uma classe de observador de perfil de arquivo, estendendo a classe do mip::FileProfile::Observer SDK. O observador é instanciado e usado posteriormente, para monitorar o carregamento do objeto de perfil File e adicionar o objeto Engine ao perfil.

  1. Adicione uma nova classe ao seu projeto, que gera os arquivos header/.h e implementation/.cpp para você:

    • No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto novamente, selecione Adicionar e, em seguida, selecione Classe.

    • Na caixa de diálogo Adicionar classe:

      • No campo Nome da classe, digite "profile_observer". Observe que os campos de arquivo .h e arquivo .cpp são preenchidos automaticamente, com base no nome inserido.
      • Quando terminar, clique no botão OK .

      Visual Studio add class

  2. Depois de gerar os arquivos .h e .cpp para a classe, ambos os arquivos são abertos nas guias Grupo de Editores. Agora atualize cada arquivo para implementar sua nova classe de observador:

    • Atualize "profile_observer.h", selecionando/excluindo a classe gerada profile_observer . Não remova as diretivas de pré-processador geradas pela etapa anterior (#pragma, #include). Em seguida, copie/cole a seguinte fonte no arquivo, após quaisquer diretivas de pré-processador existentes:

      #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;
      };
      
    • Atualize "profile_observer.cpp", selecionando/excluindo a implementação da classe gerada profile_observer . Não remova as diretivas de pré-processador geradas pela etapa anterior (#pragma, #include). Em seguida, copie/cole a seguinte fonte no arquivo, após quaisquer diretivas de pré-processador existentes:

      #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. Opcionalmente, use F6 (Build Solution) para executar uma compilação/link de teste da sua solução, para garantir que ela seja compilada com êxito antes de continuar.

Implementar um delegado de autenticação

O MIP SDK implementa a autenticação usando extensibilidade de classe, que fornece um mecanismo para compartilhar o trabalho de autenticação com o aplicativo cliente. O cliente deve adquirir um token de acesso OAuth2 adequado e fornecer ao MIP SDK em tempo de execução.

Agora, crie uma implementação para um delegado de autenticação, estendendo a classe do mip::AuthDelegate SDK e substituindo/implementando a função virtual pura mip::AuthDelegate::AcquireOAuth2Token() . O delegado de autenticação é instanciado e usado posteriormente, pelos objetos File profile e File engine.

  1. Usando o mesmo recurso "Adicionar classe" do Visual Studio que usamos na etapa #1 da seção anterior, adicione outra classe ao seu projeto. Desta vez, digite "auth_delegate" no campo Nome da classe.

  2. Agora atualize cada arquivo para implementar sua nova classe de delegado de autenticação:

    • Atualize "auth_delegate.h", substituindo todo o código de classe gerado auth_delegate pela seguinte fonte. Não remova as diretivas de pré-processador geradas pela etapa anterior (#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;
      };
      
    • Atualize "auth_delegate.cpp", substituindo toda a implementação de classe gerada auth_delegate pela seguinte fonte. Não remova as diretivas de pré-processador geradas pela etapa anterior (#pragma, #include).

      Importante

      O código de aquisição de token a seguir não é adequado para uso em produção. Na produção, isso deve ser substituído por um código que adquire dinamicamente um token, usando:

      • O appId e o URI de resposta/redirecionamento especificados no registro do aplicativo Microsoft Entra (o URI de resposta/redirecionamento deve corresponder ao registro do aplicativo)
      • A autoridade e a URL do recurso passadas pelo SDK no argumento (a URL do recurso deve corresponder à API/permissões do registro do challenge aplicativo)
      • Credenciais válidas de aplicativo/usuário, onde a conta corresponde ao identity argumento passado pelo SDK. Os clientes "nativos" do OAuth2 devem solicitar credenciais de usuário e usar o fluxo de "código de autorização". Os "clientes confidenciais" OAuth2 podem usar suas próprias credenciais seguras com o fluxo de "credenciais de cliente" (como um serviço) ou solicitar credenciais de usuário usando o fluxo de "código de autorização" (como um aplicativo Web).

      A aquisição de tokens OAuth2 é um protocolo complexo e normalmente realizado usando uma biblioteca. TokenAcquireOAuth2Token() é chamado apenas pelo MIP SDK, conforme necessário.

      #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. Opcionalmente, use F6 (Build Solution) para executar uma compilação/link de teste da sua solução, para garantir que ela seja compilada com êxito antes de continuar.

Agora, crie uma implementação para um delegado de consentimento, estendendo a classe do mip::ConsentDelegate SDK e substituindo/implementando a função virtual pura mip::AuthDelegate::GetUserConsent() . O delegado de consentimento é instanciado e usado posteriormente, pelos objetos File profile e File engine.

  1. Usando o mesmo recurso "Adicionar classe" do Visual Studio que usamos anteriormente, adicione outra classe ao seu projeto. Desta vez, digite "consent_delegate" no campo Nome da classe.

  2. Agora, atualize cada arquivo para implementar sua nova classe de delegado de consentimento:

    • Atualize "consent_delegate.h", substituindo todo o código de classe gerado consent_delegate pela seguinte fonte. Não remova as diretivas de pré-processador geradas pela etapa anterior (#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;
      };
      
    • Atualize "consent_delegate.cpp", substituindo toda a implementação de classe gerada consent_delegate pela seguinte fonte. Não remova as diretivas de pré-processador geradas pela etapa anterior (#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. Opcionalmente, use F6 (Build Solution) para executar uma compilação/link de teste da sua solução, para garantir que ela seja compilada com êxito antes de continuar.

Construir um perfil de arquivo e um mecanismo

Como mencionado, os objetos de perfil e mecanismo são necessários para clientes SDK que usam APIs MIP. Conclua a parte de codificação deste Guia de início rápido, adicionando código para instanciar os objetos de perfil e mecanismo:

  1. No Gerenciador de Soluções, abra o arquivo de .cpp em seu projeto que contém a main() implementação do método. O padrão é o mesmo nome do projeto que o contém, que você especificou durante a criação do projeto.

  2. Remova a implementação gerada do main(). Não remova diretivas de pré-processador geradas pelo Visual Studio durante a criação do projeto (#pragma, #include). Anexe o seguinte código após quaisquer diretivas de pré-processador:

#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. Substitua todos os valores de espaço reservado no código-fonte que você acabou de colar, usando constantes de cadeia de caracteres:

    Marcador de Posição Valor Exemplo
    <ID do aplicativo> O Microsoft Entra Application ID (GUID) atribuído ao aplicativo registrado na etapa #2 do artigo "MIP SDK setup and configuration". Substitua 2 instâncias. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <nome-aplicativo> Um nome amigável definido pelo usuário para seu aplicativo. Deve conter caracteres ASCII válidos (excluindo ';') e, idealmente, corresponde ao nome do aplicativo que você usou em seu registro do Microsoft Entra. "AppInitialization"
    <aplicação-versão> Informações de versão definidas pelo usuário para seu aplicativo. Deve conter caracteres ASCII válidos (excluindo ';'). "1.1.0.0"
    <conta-motor> A conta usada para a identidade do mecanismo. Quando você se autentica com uma conta de usuário durante a aquisição do token, ela deve corresponder a esse valor. "user1@tenant.onmicrosoft.com"
    <estado-motor> Estado definido pelo usuário a ser associado ao mecanismo. "My App State"
  2. Agora faça uma compilação final do aplicativo e resolva quaisquer erros. Seu código deve ser compilado com êxito, mas ainda não será executado corretamente até que você conclua o próximo Guia de início rápido. Se você executar o aplicativo, verá uma saída semelhante à seguinte. Você não terá um token de acesso para fornecer até concluir o próximo Guia de início rápido.

Passos Seguintes

Agora que o código de inicialização está concluído, você está pronto para o próximo início rápido, onde começará a experimentar os SDKs de arquivo MIP.