Краткое руководство. Инициализация клиентских приложений (C++)
В этом кратком руководстве показано, как реализовать шаблон инициализации клиентов, используемый пакетом SDK MIP для C++ во время выполнения.
Примечание.
Действия, описанные в этом кратком руководстве, применимы к любому клиентскому приложению, использующему пакеты SDK MIP File, Policy и Protection. Хотя в этом кратком руководстве показано использование пакетов SDK File, этот же шаблон применим к клиентам, использующим пакеты SDK Policy и Protection. Выполняйте оставшиеся краткие руководства последовательно, так как каждое из них основано на предыдущем, и это первое.
Необходимые компоненты
Обязательно сделайте следующее, если еще этого не сделали:
- Выполните действия, описанные в статье Установка и настройка пакета SDK Microsoft Information Protection (MIP). Для работы с кратким руководством "Инициализация клиентских приложений" требуется правильная установка и настройка пакета SDK.
- Дополнительно:
- Просмотрите раздел Объекты профиля и подсистемы. Объекты профиля и подсистемы — это универсальные понятия для клиентов, которые используют пакеты SDK MIP File, Policy и Protection.
- Изучите основные понятия проверки подлинности, чтобы узнать, как пакет SDK и клиентское приложение реализуют проверку подлинности и согласие.
- Изучите основные понятия наблюдателя, чтобы узнать о наблюдателях и их реализации. В пакете SDK MIP используется шаблон наблюдателя для реализации уведомлений об асинхронных событиях.
Создание решения и проекта Visual Studio
Сначала мы создадим и настроим первоначальное решение и проект Visual Studio для работы с другими краткими руководствами.
В Visual Studio 2017 откройте меню Файл и выберите Создать и Проект. В диалоговом окне Новый проект:
Добавьте пакет Nuget для пакета SDK MIP File в проект:
В Обозревателе решений щелкните правой кнопкой мыши узел проекта (непосредственно под верхним узлом или узлом решения) и выберите Управление пакетами NuGet:
Когда откроется вкладка Диспетчер пакетов NuGet в области вкладок группы редакторов:
- Выберите Обзор.
- Введите Microsoft.InformationProtection в поле поиска.
- Выберите пакет Microsoft.InformationProtection.File.
- Когда отобразится диалоговое окно подтверждения Предварительный просмотр изменений, щелкните "Установить" и "ОК".
Реализация класса наблюдателя для отслеживания объектов профиля и подсистемы File
Теперь создадим базовую реализацию для класса наблюдателя профиля File, расширив класс mip::FileProfile::Observer
пакета SDK. Экземпляр наблюдателя создается и используется позднее для отслеживания загрузки объекта профиля File и добавления объекта подсистемы в профиль.
Добавьте в проект новый класс, который создает файлы header/.h и implementation/.cpp:
В Обозревателе решений снова щелкните правой кнопкой мыши узел проекта, а затем выберите Добавить и Класс.
В диалоговом окне Добавить класс:
- В поле Имя класса введите profile_observer. Обратите внимание, что поля файлов .h и .cpp заполняются автоматически в зависимости от имени, которое вы вводите.
- По завершении щелкните ОК.
После создания файлов .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); }
Вы можете нажать клавишу F6 (Выполнить сборку решения) для запуска тестовой компиляции решения или переходу по ссылке на него, чтобы убедиться, что его сборка успешно выполняется, прежде чем продолжить.
Реализация делегата проверки подлинности
Пакет SDK MIP реализует проверку подлинности с использованием расширяемости класса, которая предоставляет механизм совместного использования проверки подлинности с клиентским приложением. Клиент должен получить подходящий маркер доступа OAuth2 и предоставить его пакету SDK MIP во время выполнения.
Теперь создайте реализацию для делегата проверки подлинности, расширив класс mip::AuthDelegate
пакета SDK и переопределив или реализовав чистую виртуальную функцию mip::AuthDelegate::AcquireOAuth2Token()
. Экземпляр делегата проверки подлинности создается и используется позже объектами профиля и подсистемы File.
Добавьте в проект еще один класс с помощью той же функции "Добавить класс" в Visual Studio, которая использовалась на шаге 1 предыдущего раздела. В этот раз введите auth_delegate в поле Имя класса.
Теперь обновите каждый файл, чтобы реализовать новый класс делегата проверки подлинности:
Обновите 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 должны запрашивать учетные данные пользователей и использовать поток кода авторизации. Конфиденциальные клиенты 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; }
Вы можете нажать клавишу F6 (Выполнить сборку решения) для запуска тестовой компиляции решения или переходу по ссылке на него, чтобы убедиться, что его сборка успешно выполняется, прежде чем продолжить.
Реализация делегата согласия
Теперь создайте реализацию для делегата согласия, расширив класс mip::ConsentDelegate
пакета SDK и переопределив или реализовав чистую виртуальную функцию mip::AuthDelegate::GetUserConsent()
. Экземпляр делегата согласия создается и используется позже объектами профиля и подсистемы File.
Добавьте в проект еще один класс с помощью той же функции "Добавить класс" в Visual Studio, которая использовалась ранее. В этот раз введите consent_delegate в поле Имя класса.
Теперь обновите каждый файл, чтобы реализовать новый класс делегата согласия:
Обновите 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; }
Вы можете нажать клавишу F6 (Выполнить сборку решения) для запуска тестовой компиляции решения или переходу по ссылке на него, чтобы убедиться, что его сборка успешно выполняется, прежде чем продолжить.
Создание профиля и подсистемы File
Как уже упоминалось, для клиентов пакета SDK, использующих API MIP, необходимы объекты профиля и подсистемы. Выполните часть этого краткого руководства, добавив код для создания экземпляров объектов профиля и подсистемы:
В Обозревателе решений откройте файл .cpp в проекте, содержащем реализацию метода
main()
. По умолчанию он имеет то же имя, что и содержащий его проект, который вы указали при создании проекта.Удалите созданную реализацию
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;
}
Замените все заполнители в только что вставленном вами исходном коде строковыми константами:
Заполнитель Значение Пример <application-id> Идентификатор приложения Microsoft Entra (GUID), назначенный приложению, зарегистрированным на шаге 2 статьи "Настройка и настройка пакета SDK MIP". Замените два экземпляра. "0edbblll-8773-44de-b87c-b8c6276d41eb"
<application-name> Определенное пользователем понятное имя вашего приложения. Должен содержать допустимые символы ASCII (за исключением ";") и в идеале соответствует имени приложения, используемому в регистрации Microsoft Entra. "AppInitialization"
<application-version> Определенные пользователем сведения о версии вашего приложения. Должны содержать допустимые символы ASCII (за исключением ;). "1.1.0.0"
<engine-account> Учетная запись, используемая для удостоверения подсистемы. При проверке подлинности с помощью учетной записи пользователя во время получения маркера она должна соответствовать этому значению. "user1@tenant.onmicrosoft.com"
<engine-state> Определяемое пользователем состояние, связанное с подсистемой. "My App State"
Теперь вы можете выполнить окончательную сборку приложения и устранить все ошибки. Ваш код должен быть успешно скомпилирован, но не будет работать правильно, пока вы не завершите следующее краткое руководство. При запуске приложения вы увидите результат, аналогичный указанному ниже. У вас не будет маркера доступа, который нужно предоставить, пока вы не завершите следующее краткое руководство.
Дальнейшие действия
Теперь, когда код инициализации написан, вы можете переходить к следующему краткому руководству по началу работы с пакетом SDK MIP File.