Aracılığıyla paylaş


Windows uygulamalarında OAuth 2.0 uygulama

Windows Uygulama SDK'sında OAuth2Manager , WinUI gibi masaüstü uygulamalarının Windows üzerinde sorunsuz bir şekilde OAuth 2.0 yetkilendirmesi gerçekleştirmesini sağlar. OAuth2Manager API'sinde, güvenlikle ilgili endişeler nedeniyle örtük istek ve kaynak sahibi parola kimlik bilgileri için API'ler sağlanmamıştır. Kod Değişimi için Proof Key (PKCE) ile yetkilendirme kodu verme türünü kullanın. Daha fazla bilgi için bkz . PKCE RFC.

Windows uygulamaları için OAuth 2.0 arka planı

Öncelikli olarak UWP uygulamaları için tasarlanan Windows Çalışma Zamanı (WinRT) WebAuthenticationBroker, masaüstü uygulamalarında kullanıldığında çeşitli zorluklar sunar. Temel sorunlar, masaüstü uygulama çerçeveleriyle uyumlu olmayan ApplicationView bağımlılığıdır. Sonuç olarak, geliştiricilerin WinUI ve diğer masaüstü uygulamalarına OAuth 2.0 işlevselliğini uygulamak için birlikte çalışma arabirimleri ve ek kod içeren geçici çözümlere başvurması gerekir.

Windows Uygulama SDK'sında OAuth2Manager API'si

Windows Uygulama SDK'sı için OAuth2Manager API'si, geliştiricilerin beklentilerini karşılayan kolaylaştırılmış bir çözüm sağlar. Windows Uygulama SDK'sı tarafından desteklenen tüm Windows platformlarında tam özellik eşliği ile sorunsuz OAuth 2.0 özellikleri sunar. Yeni API, hantal geçici çözümler gereksinimini ortadan kaldırır ve OAuth 2.0 işlevselliğini masaüstü uygulamalarına ekleme işlemini basitleştirir.

OAuth2Manager, WinRT'deki WebAuthenticationBroker'dan farklıdır. Örneğin kullanıcının varsayılan tarayıcısını kullanarak OAuth 2.0 en iyi yöntemlerini daha yakından izler. API için en iyi yöntemler IETF (Internet Engineering Task Force) OAuth 2.0 Authorization Framework RFC 6749, PKCE RFC 7636 ve Native Apps rfc 8252 için OAuth 2.0'dan gelir.

OAuth 2.0 kod örnekleri

GitHub'da tam bir WinUI örnek uygulaması mevcuttur. Aşağıdaki bölümlerde, OAuth2Manager API'sini kullanan en yaygın OAuth 2.0 akışları için kod parçacıkları sağlanır.

Yetkilendirme kodu isteği

Aşağıdaki örnekte, Windows Uygulama SDK'sında OAuth2Manager kullanarak bir yetkilendirme kodu isteğinin nasıl gerçekleştirilme işlemi gösterilmektedir:

// 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());
}

Erişim belirteci için Exchange yetkilendirme kodu

Aşağıdaki örnekte , OAuth2Manager kullanılarak erişim belirteci için yetkilendirme kodunun nasıl değiştirildiği gösterilmektedir.

PKCE kullanan genel istemciler (yerel masaüstü uygulamaları gibi) için istemci sırrı eklemeyin. Bunun yerine PKCE kod doğrulayıcısı güvenliği sağlar:

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());
}

gizli istemciler (web uygulamaları veya hizmetler gibi) için bir istemci sırrına sahipseniz, ClientAuthentication parametresini ekleyin:

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

Erişim belirtecini yenileme

Aşağıdaki örnek , OAuth2Manager'ınRefreshTokenAsync yöntemini kullanarak erişim belirtecinin nasıl yenilendiğini gösterir.

PKCE kullanan genel istemciler için parametresini atla 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());
}

Güvenli istemciye sahip olan ve istemci gizli anahtarı bulunanlar için parametresini ekleyin:

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

Yetkilendirme isteğini tamamlama

Protokol etkinleştirmesinden gelen yetkilendirme isteğini tamamlamak için uygulamanızın AppInstance.Activated olayını işlemesi gerekir. Bu olay, uygulamanızın özel yeniden yönlendirme mantığı olduğunda gereklidir. GitHub'da tam bir örnek mevcuttur.

Aşağıdaki kodu kullanın:

void App::OnActivated(const IActivatedEventArgs& args)
{
    if (args.Kind() == ActivationKind::Protocol)
    {
        auto protocolArgs = args.as<ProtocolActivatedEventArgs>();
        if (OAuth2Manager::CompleteAuthRequest(protocolArgs.Uri()))
        {
            TerminateCurrentProcess();
        }

        DisplayUnhandledMessageToUser();
    }
}