Поделиться через


Быстрый старт: Инициализация клиентского приложения (C++)

В этом кратком руководстве показано, как реализовать шаблон инициализации клиента, используемый пакетом SDK MIP C++ во время выполнения.

Примечание.

Действия, описанные в этом кратком руководстве, необходимы для любого клиентского приложения, использующего SDK MIP для работы с файлами, политики или защиты. Хотя в этом кратком руководстве показано использование пакетов SDK для файлов, этот же шаблон применим к клиентам с помощью пакетов SDK политики и защиты. Выполните оставшиеся инструкции последовательно, поскольку каждая из них строится на предыдущей, и это руководство — первое.

Предпосылки

Если вы еще не сделали этого, обязательно выполните следующие действия.

  • Выполните действия, описанные в настройке и конфигурации пакета SDK Microsoft Information Protection (MIP). Это краткое руководство по инициализации клиентского приложения зависит от правильной настройки пакета SDK.
  • Необязательно:
    • Просмотрите объекты профиля и движка. Объекты профиля и движка — это универсальные понятия, необходимые клиентам, использующим SDK для MIP-файлов, политик и защиты.
    • Ознакомьтесь с концепциями проверки подлинности , чтобы узнать, как проверка подлинности и согласие реализованы пакетом SDK и клиентским приложением.
    • Ознакомьтесь с концепциями наблюдателя , чтобы узнать больше о наблюдателях и о том, как они реализуются. Пакет SDK MIP использует шаблон наблюдателя для реализации асинхронных уведомлений о событиях.

Создание решения и проекта Visual Studio

Сначала мы создаём и настраиваем начальное решение и проект в Visual Studio, на которых основываются другие быстрые старты.

  1. Откройте Visual Studio 2019 или более поздней версии, выберите меню "Файл ", "Создать", "Проект". В диалоговом окне "Новый проект ":

    • В области слева в разделе "Установленные", "Другие языки" выберите Visual C++.

    • В центральной области выберите консольное приложение Windows

    • В нижней области обновите имя проекта, расположение и соответствующее имя содержащего решения .

    • По завершении нажмите кнопку "ОК " в правом нижнем углу.

      Создание решения Visual Studio

  2. Добавьте пакет NuGet для пакета SDK для файлов MIP в проект:

    • В Обозревателе решений щелкните правой кнопкой мыши по узлу проекта (непосредственно под верхним узлом или узлом решения) и выберите "Управление пакетами NuGet..."

    • Когда откроется вкладка Диспетчер пакетов NuGet в области вкладок группы редакторов:

      • Выберите Обзор.
      • В поле поиска введите "Microsoft.InformationProtection".
      • Выберите пакет Microsoft.InformationProtection.File.
      • Нажмите кнопку "Установить", а затем нажмите кнопку "ОК" при отображении диалогового окна подтверждения изменений предварительного просмотра .

      Добавление пакета NuGet в Visual Studio

Реализация класса наблюдателя для мониторинга объектов профиля файла и обработчика

Теперь создайте базовую реализацию для класса наблюдателя профиля файла, расширив класс ПАКЕТА SDK mip::FileProfile::Observer . Наблюдатель создаётся и используется позже для наблюдения за загрузкой объекта профиля файла и добавления объекта движка в профиль.

  1. Добавьте новый класс в свой проект, который автоматически генерирует для вас заголовочные файлы (.h) и файлы реализации (.cpp).

    • В обозревателе решений снова щелкните правой кнопкой мыши узел проекта, выберите "Добавить", а затем выберите "Класс".

    • На диалоговом окне Добавить класс

      • В поле "Имя класса " введите "profile_observer". Обратите внимание, что поля файлов H и .cpp автоматически заполняются в зависимости от введенного имени.
      • По завершении нажмите кнопку "ОК ".

      Добавление класса Visual Studio

  2. После создания файлов H и .cpp для класса оба файла открываются на вкладках "Группа редакторов". Теперь обновите каждый файл, чтобы реализовать новый класс наблюдателя:

    • Обновите "profile_observer.h", выбрав или удалив созданный profile_observer класс. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#pragma, #include). Затем скопируйте и вставьте следующий источник в файл после всех существующих директив препроцессора:

      #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;
      };
      
    • Обновите "profile_observer.cpp", выбрав или удалив созданную profile_observer реализацию класса. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#pragma, #include). Затем скопируйте и вставьте следующий источник в файл после всех существующих директив препроцессора:

      #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. При необходимости используйте F6 (сборка решения) для запуска тестовой компиляции/связывания вашего решения, чтобы убедиться, что она успешно выполняется перед тем как продолжить.

Внедрить делегата проверки подлинности

Пакет SDK MIP реализует проверку подлинности с помощью расширяемости классов, что позволяет совместно использовать задачу аутентификации с клиентским приложением. Клиент должен получить подходящий токен доступа OAuth2 и предоставить его SDK MIP во время выполнения.

Теперь создайте реализацию для делегата проверки подлинности, расширив класс пакета SDK mip::AuthDelegate и переопределяя или реализуя чистую виртуальную mip::AuthDelegate::AcquireOAuth2Token() функцию. Делегат проверки подлинности создается и используется позже объектами профиля файлов и обработчика файлов.

  1. Используя ту же функцию Visual Studio "Добавить класс", которую мы использовали на шаге 1 предыдущего раздела, добавьте в проект другой класс. На этот раз введите "auth_delegate" в поле "Имя класса ".

  2. Теперь обновите каждый файл, чтобы реализовать новый класс делегата проверки подлинности:

    • Обновите файл "auth_delegate.h", заменив весь созданный auth_delegate код класса следующим источником. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#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;
      };
      
    • Обновите "auth_delegate.cpp", заменив весь сгенерированный код реализации класса auth_delegate следующим кодом. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#pragma, #include).

      Это важно

      Следующий код получения токена не подходит для использования в промышленной среде. В рабочей среде это должно быть заменено кодом, динамически получающим маркер, с помощью:

      • Идентификатор приложения и URI ответа или перенаправления, указанный в регистрации приложения Microsoft Entra (URI ответа или перенаправления должен совпадать с регистрацией вашего приложения).
      • URL-адрес центра и ресурса, переданный пакетом SDK в аргументе challenge (URL-адрес ресурса должен соответствовать API и разрешениям регистрации приложения).
      • Допустимые учетные данные приложения или пользователя, где учетная запись соответствует аргументу identity , передаваемого пакетом SDK. Клиенты OAuth2 "native" должны запрашивать учетные данные пользователя и использовать процесс "авторизационного кода". OAuth2 "конфиденциальные клиенты" могут использовать свои собственные безопасные учетные данные с потоком "учетные данные клиента" (например, служба) или запрашивать учетные данные пользователей с помощью потока "код авторизации" (например, веб-приложение).

      Получение маркера OAuth2 — это сложный протокол, который обычно выполняется с помощью библиотеки. TokenAcquireOAuth2Token() вызывается только пакетом SDK MIP по мере необходимости.

      #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. При необходимости используйте F6 (сборка решения) для запуска тестовой компиляции/связывания вашего решения, чтобы убедиться, что она успешно выполняется перед тем как продолжить.

Теперь создайте реализацию для делегата согласия, расширив класс пакета SDK mip::ConsentDelegate и переопределяя или реализуя чистую виртуальную mip::AuthDelegate::GetUserConsent() функцию. Делегат согласия создается и используется позже объектами профиля файлов и обработчика файлов.

  1. Используя ту же функцию Visual Studio "Добавить класс", которую мы использовали ранее, добавьте другой класс в проект. На этот раз введите "consent_delegate" в поле "Имя класса ".

  2. Теперь обновите каждый файл, чтобы реализовать новый класс делегата согласия:

    • Обновите файл "consent_delegate.h", заменив весь созданный consent_delegate код класса следующим источником. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#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;
      };
      
    • Обновите "consent_delegate.cpp", заменив всю созданную consent_delegate реализацию класса следующим кодом. Не удаляйте директивы препроцессора, созданные на предыдущем шаге (#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. При необходимости используйте F6 (сборка решения) для запуска тестовой компиляции/связывания вашего решения, чтобы убедиться, что она успешно выполняется перед тем как продолжить.

Создание профиля файла и движка

Как упоминалось, для клиентов пакета SDK с использованием API MIP требуются объекты профиля и движка. Завершите часть этого краткого руководства по программированию, добавив код для создания экземпляров объектов профиля и движка.

  1. В обозревателе решений откройте файл .cpp в проекте, который содержит реализацию main() метода. По умолчанию используется то же имя, что и проект, содержащий его, указанный во время создания проекта.

  2. Удалите созданную реализацию main(). Не удаляйте директивы препроцессора, созданные Visual Studio во время создания проекта (#pragma, #include). Добавьте следующий код после любых директив препроцессора:

#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. Замените все значения заполнителей в исходном коде, вставленном только что с помощью строковых констант:

    Замещающее поле Ценность Пример
    <идентификатор приложения> Идентификатор приложения Microsoft Entra (GUID), назначенный приложению, зарегистрированным на шаге 2 статьи "Настройка и настройка пакета SDK MIP". Замените 2 вхождения. "0edbblll-8773-44de-b87c-b8c6276d41eb"
    <имя приложения> Пользовательское понятное имя для вашего приложения. Должен содержать допустимые символы ASCII (за исключением ";") и в идеале соответствует имени приложения, используемому в регистрации Microsoft Entra. "AppInitialization"
    <версия приложения> Определяемые пользователем сведения о версии приложения. Должен содержать допустимые символы ASCII (за исключением ";"). "1.1.0.0"
    <учетная запись двигателя> Учетная запись, используемая для идентификации движка. При проверке подлинности с учетной записью пользователя во время приобретения токена учетная запись должна соответствовать этому значению. "user1@tenant.onmicrosoft.com"
    <состояние подсистемы> Определяемое пользователем состояние, связанное с движком. "My App State"
  2. Теперь выполните окончательную сборку приложения и устраните все ошибки. Код должен успешно скомпилироваться, но еще не будет работать правильно, пока вы не завершите следующий шаг. При запуске приложения вы увидите выходные данные, аналогичные приведенным ниже. У вас не будет токена доступа, пока не выполните следующее краткое руководство.

Дальнейшие шаги

Теперь, когда код инициализации завершен, вы готовы к следующему этапу быстрого начала, где вы начнете изучать инструментарий SDK файлов MIP.