Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
OAuth2Manager в пакете SDK для приложений Windows позволяет классическим приложениям, таким как WinUI 3, легко выполнять авторизацию OAuth 2.0 в Windows. API OAuth2Manager не предоставляет API для неявного запроса и учетных данных владельца ресурса из-за проблем безопасности, которые влечет за собой. Используйте тип выдачи авторизационного кода с PKCE (Proof Key for Code Exchange). Дополнительную информацию см. в PKCE RFC.
Фон OAuth 2.0 для приложений Windows
Среда выполнения Windows (WinRT) WebAuthenticationBroker, предназначенная в первую очередь для приложений UWP, представляет несколько проблем при использовании в настольных приложениях. Ключевые проблемы включают зависимость от ApplicationView, которая несовместима с платформами настольных приложений. В результате разработчики должны прибегнуть к обходным решениям, связанным с интерфейсами взаимодействия и дополнительным кодом для реализации функций OAuth 2.0 в WinUI и других классических приложениях.
API OAuth2Manager в пакете SDK для приложений Windows
API OAuth2Manager для пакета SDK для приложений Windows предоставляет упрощенное решение, которое соответствует ожиданиям разработчиков. Он предлагает удобные возможности OAuth 2.0 с полной четностью функций на всех платформах Windows, поддерживаемых пакетом SDK для приложений Windows. Новый API устраняет необходимость обходных решений и упрощает процесс включения функций OAuth 2.0 в классические приложения.
OAuth2Manager отличается от WebAuthenticationBroker в WinRT. Он следует лучшим практикам OAuth 2.0 более строго - например, используя браузер пользователя по умолчанию. Рекомендации по API поступают из IETF (Группа задач по разработке Интернета) OAuth 2.0 Authorization Framework RFC 6749, PKCE RFC 7636 и OAuth 2.0 для собственных приложений RFC 8252.
Примеры кода OAuth 2.0
Полный пример приложения WinUI доступен на сайте GitHub. В следующих разделах приведены фрагменты кода для наиболее распространенных потоков OAuth 2.0 с помощью API OAuth2Manager.
Запрос кода авторизации
В следующем примере показано, как выполнить запрос кода авторизации с помощью OAuth2Manager в пакете SDK для приложений Windows:
// Get the WindowId for the application window
Microsoft::UI::WindowId parentWindowId = this->AppWindow().Id();
AuthRequestParams authRequestParams = AuthRequestParams::CreateForAuthorizationCodeRequest(L"my_client_id",
Uri(L"my-app:/oauth-callback/"));
authRequestParams.Scope(L"user:email user:birthday");
AuthRequestResult authRequestResult = co_await OAuth2Manager::RequestAuthWithParamsAsync(parentWindowId,
Uri(L"https://my.server.com/oauth/authorize"), authRequestParams);
if (AuthResponse authResponse = authRequestResult.Response())
{
//To obtain the authorization code
//authResponse.Code();
//To obtain the access token
DoTokenExchange(authResponse);
}
else
{
AuthFailure authFailure = authRequestResult.Failure();
NotifyFailure(authFailure.Error(), authFailure.ErrorDescription());
}
Обменять код авторизации на токен доступа
В следующем примере показано, как обменять код авторизации на маркер доступа с помощью OAuth2Manager.
Для общедоступных клиентов (например, собственных классических приложений), использующих PKCE, не включайте секрет клиента. Средство проверки кода PKCE обеспечивает безопасность вместо этого.
AuthResponse authResponse = authRequestResult.Response();
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForAuthorizationCodeRequest(authResponse);
// For public clients using PKCE, do not include ClientAuthentication
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
Uri(L"https://my.server.com/oauth/token"), tokenRequestParams);
if (TokenResponse tokenResponse = tokenRequestResult.Response())
{
String accessToken = tokenResponse.AccessToken();
String tokenType = tokenResponse.TokenType();
// RefreshToken string null/empty when not present
if (String refreshToken = tokenResponse.RefreshToken(); !refreshToken.empty())
{
// ExpiresIn is zero when not present
DateTime expires = winrt::clock::now();
if (String expiresIn = tokenResponse.ExpiresIn(); std::stoi(expiresIn) != 0)
{
expires += std::chrono::seconds(static_cast<int64_t>(std::stoi(expiresIn)));
}
else
{
// Assume a duration of one hour
expires += std::chrono::hours(1);
}
//Schedule a refresh of the access token
myAppState.ScheduleRefreshAt(expires, refreshToken);
}
// Use the access token for resources
DoRequestWithToken(accessToken, tokenType);
}
else
{
TokenFailure tokenFailure = tokenRequestResult.Failure();
NotifyFailure(tokenFailure.Error(), tokenFailure.ErrorDescription());
}
Для конфиденциальных клиентов (например, веб-приложений или служб), имеющих секрет клиента, включите ClientAuthentication параметр:
AuthResponse authResponse = authRequestResult.Response();
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForAuthorizationCodeRequest(authResponse);
ClientAuthentication clientAuth = ClientAuthentication::CreateForBasicAuthorization(L"my_client_id",
L"my_client_secret");
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
Uri(L"https://my.server.com/oauth/token"), tokenRequestParams, clientAuth);
// Handle the response as shown in the previous example
Обновить токен доступа
В следующем примере показано, как обновить маркер доступа с помощью метода RefreshTokenAsyncOAuth2Manager.
Для общедоступных клиентов , использующих PKCE, опустите ClientAuthentication параметр:
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForRefreshToken(refreshToken);
// For public clients using PKCE, do not include ClientAuthentication
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
Uri(L"https://my.server.com/oauth/token"), tokenRequestParams);
if (TokenResponse tokenResponse = tokenRequestResult.Response())
{
UpdateToken(tokenResponse.AccessToken(), tokenResponse.TokenType(), tokenResponse.ExpiresIn());
//Store new refresh token if present
if (String refreshToken = tokenResponse.RefreshToken(); !refreshToken.empty())
{
// ExpiresIn is zero when not present
DateTime expires = winrt::clock::now();
if (String expiresInStr = tokenResponse.ExpiresIn(); !expiresInStr.empty())
{
int expiresIn = std::stoi(expiresInStr);
if (expiresIn != 0)
{
expires += std::chrono::seconds(static_cast<int64_t>(expiresIn));
}
}
else
{
// Assume a duration of one hour
expires += std::chrono::hours(1);
}
//Schedule a refresh of the access token
myAppState.ScheduleRefreshAt(expires, refreshToken);
}
}
else
{
TokenFailure tokenFailure = tokenRequestResult.Failure();
NotifyFailure(tokenFailure.Error(), tokenFailure.ErrorDescription());
}
Для конфиденциальных клиентов , имеющих секрет клиента, включите ClientAuthentication параметр:
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForRefreshToken(refreshToken);
ClientAuthentication clientAuth = ClientAuthentication::CreateForBasicAuthorization(L"my_client_id",
L"my_client_secret");
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
Uri(L"https://my.server.com/oauth/token"), tokenRequestParams, clientAuth);
// Handle the response as shown in the previous example
Завершение запроса авторизации
Чтобы завершить запрос авторизации при активации протокола, приложение должно обрабатывать событие AppInstance.Activated. Это событие необходимо, если приложение имеет пользовательскую логику перенаправления. Полный пример доступен на GitHub.
Используйте следующий код:
void App::OnActivated(const IActivatedEventArgs& args)
{
if (args.Kind() == ActivationKind::Protocol)
{
auto protocolArgs = args.as<ProtocolActivatedEventArgs>();
if (OAuth2Manager::CompleteAuthRequest(protocolArgs.Uri()))
{
TerminateCurrentProcess();
}
DisplayUnhandledMessageToUser();
}
}
Связанный контент
Windows developer